IME Viewers.

IM Clients, Service and Manager Service viewers - not yet including new
WM/SF combined properties view in hierarchy.

Bug: b/238088679
Test: npm run test:all

Change-Id: I4bd05ca5dff14abbf6d3a89b0e07730233edf1b0
This commit is contained in:
Priyanka Patel
2022-09-20 11:05:26 +00:00
parent 8e8609219a
commit 32c0ee72db
35 changed files with 1238 additions and 19 deletions

View File

@@ -41,12 +41,14 @@ import { TreeNodePropertiesDataViewComponent } from "viewers/components/tree_nod
import { PropertyGroupsComponent } from "viewers/components/property_groups.component";
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";
@NgModule({
declarations: [
AppComponent,
ViewerWindowManagerComponent,
ViewerSurfaceFlingerComponent,
ViewerInputMethodComponent,
CollectTracesComponent,
UploadTracesComponent,
AdbProxyComponent,

View File

@@ -22,6 +22,7 @@ import { ViewerWindowManagerComponent } from "viewers/viewer_window_manager/view
import { ViewerSurfaceFlingerComponent } from "viewers/viewer_surface_flinger/viewer_surface_flinger.component";
import { Timestamp } from "common/trace/timestamp";
import { MatSliderChange } from "@angular/material/slider";
import { ViewerInputMethodComponent } from "viewers/components/viewer_input_method.component";
@Component({
selector: "app-root",
@@ -128,6 +129,10 @@ export class AppComponent {
customElements.define("viewer-surface-flinger",
createCustomElement(ViewerSurfaceFlingerComponent, {injector}));
}
if (!customElements.get("viewer-input-method")) {
customElements.define("viewer-input-method",
createCustomElement(ViewerInputMethodComponent, {injector}));
}
}
public updateCurrentTimestamp(event: MatSliderChange) {

View File

@@ -17,6 +17,9 @@ import {Timestamp, TimestampType} from "common/trace/timestamp";
import {TraceType} from "common/trace/trace_type";
import {Parser} from "./parser";
import {InputMethodClientsTraceFileProto} from "./proto_types";
import { TraceTreeNode } from "common/trace/trace_tree_node";
import { StringUtils } from "common/utils/string_utils";
import { ImeUtils } from "viewers/common/ime_utils";
class ParserInputMethodClients extends Parser {
constructor(trace: File) {
@@ -54,8 +57,25 @@ class ParserInputMethodClients extends Parser {
return undefined;
}
override processDecodedEntry(entryProto: any): any {
return entryProto;
override processDecodedEntry(entryProto: TraceTreeNode): TraceTreeNode {
return {
name: StringUtils.nanosecondsToHuman(entryProto.elapsedRealtimeNanos ?? 0) + " - " + entryProto.where,
kind: "InputMethodClient entry",
children: [
{
obj: ImeUtils.transformInputConnectionCall(entryProto.client),
kind: "Client",
name: entryProto.client?.viewRootImpl?.view ?? "",
children: [],
stableId: "client",
id: "client",
}
],
obj: entryProto,
stableId: "entry",
id: "entry",
elapsedRealtimeNanos: entryProto.elapsedRealtimeNanos,
};
}
private realToElapsedTimeOffsetNs: undefined|bigint;

View File

@@ -15,6 +15,8 @@
*/
import {Timestamp, TimestampType} from "common/trace/timestamp";
import {TraceType} from "common/trace/trace_type";
import { TraceTreeNode } from "common/trace/trace_tree_node";
import { StringUtils } from "common/utils/string_utils";
import {Parser} from "./parser";
import {InputMethodManagerServiceTraceFileProto} from "./proto_types";
@@ -53,8 +55,25 @@ class ParserInputMethodManagerService extends Parser {
return undefined;
}
protected override processDecodedEntry(entryProto: any): any {
return entryProto;
protected override processDecodedEntry(entryProto: TraceTreeNode): TraceTreeNode {
return {
name: StringUtils.nanosecondsToHuman(entryProto.elapsedRealtimeNanos ?? 0) + " - " + entryProto.where,
kind: "InputMethodManagerService entry",
children: [
{
obj: entryProto.inputMethodManagerService,
kind: "InputMethodManagerService",
name: "",
children: [],
stableId: "managerservice",
id: "managerservice",
}
],
obj: entryProto,
stableId: "entry",
id: "entry",
elapsedRealtimeNanos: entryProto.elapsedRealtimeNanos,
};
}
private realToElapsedTimeOffsetNs: undefined|bigint;

View File

@@ -15,7 +15,6 @@
*/
import {Timestamp, TimestampType} from "common/trace/timestamp";
import {TraceType} from "common/trace/trace_type";
import {ParserFactory} from "./parser_factory";
import {Parser} from "./parser";
import {UnitTestUtils} from "test/unit/utils";

View File

@@ -15,6 +15,9 @@
*/
import {Timestamp, TimestampType} from "common/trace/timestamp";
import {TraceType} from "common/trace/trace_type";
import { TraceTreeNode } from "common/trace/trace_tree_node";
import { StringUtils } from "common/utils/string_utils";
import { ImeUtils } from "viewers/common/ime_utils";
import {Parser} from "./parser";
import {InputMethodServiceTraceFileProto} from "./proto_types";
@@ -53,8 +56,25 @@ class ParserInputMethodService extends Parser {
return undefined;
}
override processDecodedEntry(entryProto: any): any {
return entryProto;
override processDecodedEntry(entryProto: TraceTreeNode): TraceTreeNode {
return {
name: StringUtils.nanosecondsToHuman(entryProto.elapsedRealtimeNanos ?? 0) + " - " + entryProto.where,
kind: "InputMethodService entry",
children: [
{
obj: ImeUtils.transformInputConnectionCall(entryProto.inputMethodService),
kind: "InputMethodService",
name: "",
children: [],
stableId: "service",
id: "service",
}
],
obj: entryProto,
stableId: "entry",
id: "entry",
elapsedRealtimeNanos: entryProto.elapsedRealtimeNanos,
};
}
private realToElapsedTimeOffsetNs: undefined|bigint;

View File

@@ -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 {browser, element, by} from "protractor";
import {E2eTestUtils} from "./utils";
describe("Viewer InputMethodClients", () => {
beforeAll(async () => {
browser.manage().timeouts().implicitlyWait(1000);
browser.get("file://" + E2eTestUtils.getProductionIndexHtmlPath());
}),
it("processes trace and renders view", async () => {
const inputFile = element(by.css("input[type=\"file\"]"));
await inputFile.sendKeys(E2eTestUtils.getFixturePath("traces/elapsed_and_real_timestamp/InputMethodClients.pb"));
const loadData = element(by.css(".load-btn"));
await loadData.click();
const viewerPresent = await element(by.css("viewer-input-method")).isPresent();
expect(viewerPresent).toBeTruthy();
});
});

View File

@@ -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 {browser, element, by} from "protractor";
import {E2eTestUtils} from "./utils";
describe("Viewer InputMethodManagerService", () => {
beforeAll(async () => {
browser.manage().timeouts().implicitlyWait(1000);
browser.get("file://" + E2eTestUtils.getProductionIndexHtmlPath());
}),
it("processes trace and renders view", async () => {
const inputFile = element(by.css("input[type=\"file\"]"));
await inputFile.sendKeys(E2eTestUtils.getFixturePath("traces/elapsed_and_real_timestamp/InputMethodManagerService.pb"));
const loadData = element(by.css(".load-btn"));
await loadData.click();
const viewerPresent = await element(by.css("viewer-input-method")).isPresent();
expect(viewerPresent).toBeTruthy();
});
});

View File

@@ -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 {browser, element, by} from "protractor";
import {E2eTestUtils} from "./utils";
describe("Viewer InputMethodService", () => {
beforeAll(async () => {
browser.manage().timeouts().implicitlyWait(1000);
browser.get("file://" + E2eTestUtils.getProductionIndexHtmlPath());
}),
it("processes trace and renders view", async () => {
const inputFile = element(by.css("input[type=\"file\"]"));
await inputFile.sendKeys(E2eTestUtils.getFixturePath("traces/elapsed_and_real_timestamp/InputMethodService.pb"));
const loadData = element(by.css(".load-btn"));
await loadData.click();
const viewerPresent = await element(by.css("viewer-input-method")).isPresent();
expect(viewerPresent).toBeTruthy();
});
});

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {browser, element, by, ElementFinder} from "protractor";
import {browser, element, by} from "protractor";
import {E2eTestUtils} from "./utils";
describe("Viewer SurfaceFlinger", () => {

View File

@@ -41,7 +41,7 @@ class HierarchyTreeBuilder {
diffType?: string;
skip?: any;
setId(id: number) {
setId(id: string | number) {
this.id = id;
return this;
}

View File

@@ -38,6 +38,18 @@ class UnitTestUtils extends CommonTestUtils {
return await this.getTraceEntry("traces/elapsed_timestamp/SurfaceFlinger.pb");
}
static async getInputMethodClientsEntry(): Promise<LayerTraceEntry> {
return await this.getTraceEntry("traces/elapsed_timestamp/InputMethodClients.pb");
}
static async getInputMethodServiceEntry(): Promise<LayerTraceEntry> {
return await this.getTraceEntry("traces/elapsed_timestamp/InputMethodService.pb");
}
static async getInputMethodManagerServiceEntry(): Promise<LayerTraceEntry> {
return await this.getTraceEntry("traces/elapsed_timestamp/InputMethodManagerService.pb");
}
private static async getTraceEntry(filename: string) {
const parser = await this.getParser(filename);
const timestamp = parser.getTimestamps(TimestampType.ELAPSED)![0];

View File

@@ -0,0 +1,182 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImeUiData } from "./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";
export type NotifyImeViewCallbackType = (uiData: ImeUiData) => void;
export class ImePresenter {
constructor(
notifyViewCallback: NotifyImeViewCallbackType,
dependencies: Array<TraceType>
) {
this.notifyViewCallback = notifyViewCallback;
this.dependencies = dependencies;
this.uiData = new ImeUiData(dependencies);
this.notifyViewCallback(this.uiData);
}
public updatePinnedItems(pinnedItem: HierarchyTreeNode) {
const pinnedId = `${pinnedItem.id}`;
if (this.pinnedItems.map(item => `${item.id}`).includes(pinnedId)) {
this.pinnedItems = this.pinnedItems.filter(pinned => `${pinned.id}` != pinnedId);
} else {
this.pinnedItems.push(pinnedItem);
}
this.updatePinnedIds(pinnedId);
this.uiData.pinnedItems = this.pinnedItems;
this.notifyViewCallback(this.uiData);
}
public updateHighlightedItems(id: string) {
if (this.highlightedItems.includes(id)) {
this.highlightedItems = this.highlightedItems.filter(hl => hl != id);
} else {
this.highlightedItems = []; //if multi-select surfaces implemented, remove this line
this.highlightedItems.push(id);
}
this.uiData.highlightedItems = this.highlightedItems;
this.notifyViewCallback(this.uiData);
}
public updateHierarchyTree(userOptions: UserOptions) {
this.hierarchyUserOptions = userOptions;
this.uiData.hierarchyUserOptions = this.hierarchyUserOptions;
this.uiData.tree = this.generateTree();
this.notifyViewCallback(this.uiData);
}
public filterHierarchyTree(filterString: string) {
this.hierarchyFilter = TreeUtils.makeNodeFilter(filterString);
this.uiData.tree = this.generateTree();
this.notifyViewCallback(this.uiData);
}
public updatePropertiesTree(userOptions: UserOptions) {
this.propertiesUserOptions = userOptions;
this.uiData.propertiesUserOptions = this.propertiesUserOptions;
this.updateSelectedTreeUiData();
}
public filterPropertiesTree(filterString: string) {
this.propertiesFilter = TreeUtils.makeNodeFilter(filterString);
this.updateSelectedTreeUiData();
}
public newPropertiesTree(selectedItem: HierarchyTreeNode) {
this.selectedHierarchyTree = selectedItem;
this.updateSelectedTreeUiData();
}
public notifyCurrentTraceEntries(entries: Map<TraceType, [any, any]>) {
this.uiData = new ImeUiData(this.dependencies);
this.uiData.hierarchyUserOptions = this.hierarchyUserOptions;
this.uiData.propertiesUserOptions = this.propertiesUserOptions;
const 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();
}
}
this.notifyViewCallback(this.uiData);
}
private updateSelectedTreeUiData() {
if (this.selectedHierarchyTree) {
this.uiData.propertiesTree = this.getTreeWithTransformedProperties(this.selectedHierarchyTree);
}
this.notifyViewCallback(this.uiData);
}
private generateTree() {
if (!this.entry) {
return null;
}
const generator = new TreeGenerator(this.entry, this.hierarchyFilter, this.pinnedIds)
.setIsOnlyVisibleView(this.hierarchyUserOptions["onlyVisible"]?.enabled)
.setIsSimplifyNames(this.hierarchyUserOptions["simplifyNames"]?.enabled)
.setIsFlatView(this.hierarchyUserOptions["flat"]?.enabled)
.withUniqueNodeId();
const tree: HierarchyTreeNode | null = generator.generateTree();
this.pinnedItems = generator.getPinnedItems();
this.uiData.pinnedItems = this.pinnedItems;
return tree;
}
private updatePinnedIds(newId: string) {
if (this.pinnedIds.includes(newId)) {
this.pinnedIds = this.pinnedIds.filter(pinned => pinned != newId);
} else {
this.pinnedIds.push(newId);
}
}
private getTreeWithTransformedProperties(selectedTree: HierarchyTreeNode): PropertiesTreeNode {
const transformer = new TreeTransformer(selectedTree, this.propertiesFilter)
.setIsShowDefaults(this.propertiesUserOptions["showDefaults"]?.enabled)
.setTransformerOptions({skip: selectedTree.skip})
.setProperties(this.entry);
const transformedTree = transformer.transform();
return transformedTree;
}
readonly notifyViewCallback: NotifyImeViewCallbackType;
readonly dependencies: Array<TraceType>;
uiData: ImeUiData;
private hierarchyFilter: FilterType = TreeUtils.makeNodeFilter("");
private propertiesFilter: FilterType = TreeUtils.makeNodeFilter("");
private highlightedItems: Array<string> = [];
private pinnedItems: Array<HierarchyTreeNode> = [];
private pinnedIds: Array<string> = [];
private selectedHierarchyTree: HierarchyTreeNode | null = null;
private entry: any = null;
private hierarchyUserOptions: UserOptions = {
simplifyNames: {
name: "Simplify names",
enabled: true
},
onlyVisible: {
name: "Only visible",
enabled: false
},
flat: {
name: "Flat",
enabled: false
}
};
private propertiesUserOptions: UserOptions = {
showDefaults: {
name: "Show defaults",
enabled: true,
tooltip: `
If checked, shows the value of all properties.
Otherwise, hides all properties whose value is
the default for its data type.
`
},
};
}

View File

@@ -0,0 +1,154 @@
/*
* 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<TraceType, any>;
let selectedTree: HierarchyTreeNode;
beforeAll(async () => {
entries = new Map<TraceType, any>();
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<TraceType, any>();
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);
});
});

View File

@@ -0,0 +1,150 @@
/*
* 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<TraceType, any>;
let selectedTree: HierarchyTreeNode;
beforeAll(async () => {
entries = new Map<TraceType, any>();
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<TraceType, any>();
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);
});
});

View File

@@ -0,0 +1,149 @@
/*
* 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<TraceType, any>;
let selectedTree: HierarchyTreeNode;
beforeAll(async () => {
entries = new Map<TraceType, any>();
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<TraceType, any>();
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);
});
});

View File

@@ -0,0 +1,32 @@
/*
* 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 { HierarchyTreeNode, PropertiesTreeNode } from "./ui_tree_utils";
import { UserOptions } from "viewers/common/user_options";
import { TraceType } from "common/trace/trace_type";
export class ImeUiData {
dependencies: Array<TraceType>;
highlightedItems: Array<string> = [];
pinnedItems: Array<HierarchyTreeNode> = [];
hierarchyUserOptions: UserOptions = {};
propertiesUserOptions: UserOptions = {};
tree: HierarchyTreeNode | null = null;
propertiesTree: PropertiesTreeNode | null = null;
constructor(dependencies?: Array<TraceType>) {
this.dependencies = dependencies ?? [];
}
}

View File

@@ -99,6 +99,17 @@ class ImeUtils {
);
}
public static transformInputConnectionCall(entry: any) {
const obj = Object.assign({}, entry);
if (obj.inputConnectionCall) {
Object.getOwnPropertyNames(obj.inputConnectionCall).forEach(name => {
const value = Object.getOwnPropertyDescriptor(obj.inputConnectionCall, name);
if (!value?.value) delete obj.inputConnectionCall[name];
});
}
return obj;
}
private static findAncestorTaskLayerOfImeLayer(entry: LayerTraceEntry, isTargetImeLayer: FilterType): Layer {
const imeLayer = TreeUtils.findDescendantNode(entry, isTargetImeLayer);
if (!imeLayer) {

View File

@@ -234,7 +234,7 @@ export class TreeGenerator {
}
if (this.isOnlyVisibleView) {
newTree.showInOnlyVisibleView = newTree.isVisible;
newTree.showInOnlyVisibleView = UiTreeUtils.isParentNode(tree.kind) ? true : newTree.isVisible;
}
newTree.children = [];

View File

@@ -96,5 +96,11 @@ export class UiTreeUtils
return this.PARENT_NODE_KINDS.includes(kind);
}
private static readonly PARENT_NODE_KINDS = ["entry", "WindowManagerState"];
private static readonly PARENT_NODE_KINDS = [
"entry",
"WindowManagerState",
"InputMethodClient entry",
"InputMethodService entry",
"InputMethodManagerService entry"
];
}

View File

@@ -0,0 +1,62 @@
/*
* 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 {Viewer} from "viewers/viewer";
import {ViewerEvents} from "viewers/common/viewer_events";
import { ImePresenter } from "viewers/common/ime_presenter";
import { ImeUiData } from "viewers/common/ime_ui_data";
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));
}
public notifyCurrentTraceEntries(entries: Map<TraceType, any>): void {
this.presenter.notifyCurrentTraceEntries(entries);
}
public getView(): HTMLElement {
return this.view;
}
public getTitle(): string {
return "";
}
public getDependencies(): TraceType[] {
return ViewerInputMethod.DEPENDENCIES;
}
public static readonly DEPENDENCIES: TraceType[] = [];
private view: HTMLElement;
private presenter: ImePresenter;
}
export {ViewerInputMethod};

View File

@@ -51,7 +51,7 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
</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>
<span *ngIf="objectKeys(propertiesTree).length > 0 && isProtoDump" class="properties-title"> Properties - Proto Dump </span>
<div class="tree-wrapper">
<tree-view
class="tree-view"
@@ -138,6 +138,7 @@ export class PropertiesComponent {
@Input() propertiesTree: PropertiesTreeNode = {};
@Input() selectedFlickerItem: TraceTreeNode | null = null;
@Input() propertyGroups = false;
@Input() isProtoDump = false;
constructor(
@Inject(ElementRef) private elementRef: ElementRef,

View File

@@ -44,7 +44,7 @@ export class TreeNodeDataViewComponent {
}
public itemShortName() {
return (this.item instanceof HierarchyTreeNode)? this.item.shortName : "";
return (this.item instanceof HierarchyTreeNode && this.item.shortName) ? this.item.shortName : this.item.name;
}
public itemTooltip() {
@@ -55,7 +55,7 @@ export class TreeNodeDataViewComponent {
}
public showShortName() {
return (this.item instanceof HierarchyTreeNode) && this.item.simplifyNames && this.item.shortName !== this.item.name;
return (this.item instanceof HierarchyTreeNode) && this.item.simplifyNames && this.item.shortName && this.item.shortName !== this.item.name;
}
public chipClass(chip: Chip) {

View File

@@ -0,0 +1,67 @@
/*
* 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 { ViewerInputMethodComponent } from "./viewer_input_method.component";
import { HierarchyComponent } from "viewers/components/hierarchy.component";
import { PropertiesComponent } from "viewers/components/properties.component";
import { MatIconModule } from "@angular/material/icon";
import { MatCardModule } from "@angular/material/card";
import { ComponentFixtureAutoDetect } from "@angular/core/testing";
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from "@angular/core";
describe("ViewerInputMethodComponent", () => {
let fixture: ComponentFixture<ViewerInputMethodComponent>;
let component: ViewerInputMethodComponent;
let htmlElement: HTMLElement;
beforeAll(async () => {
await TestBed.configureTestingModule({
providers: [
{ provide: ComponentFixtureAutoDetect, useValue: true }
],
imports: [
MatIconModule,
MatCardModule
],
declarations: [
ViewerInputMethodComponent,
HierarchyComponent,
PropertiesComponent,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ViewerInputMethodComponent);
component = fixture.componentInstance;
htmlElement = fixture.nativeElement;
});
it("can be created", () => {
expect(component).toBeTruthy();
});
it("creates hierarchy view", () => {
const hierarchyView = htmlElement.querySelector(".hierarchy-view");
expect(hierarchyView).toBeTruthy();
});
it("creates properties view", () => {
const propertiesView = htmlElement.querySelector(".properties-view");
expect(propertiesView).toBeTruthy();
});
});

View File

@@ -0,0 +1,113 @@
/*
* 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 { TRACE_INFO } from "app/trace_info";
import { TraceType } from "common/trace/trace_type";
import { PersistentStore } from "common/persistent_store";
import { ImeUiData } from "viewers/common/ime_ui_data";
@Component({
selector: "viewer-input-method",
template: `
<div fxLayout="row wrap" fxLayoutGap="10px grid" class="card-grid">
<mat-card class="hierarchy-view">
<hierarchy-view
[tree]="inputData?.tree ?? null"
[dependencies]="inputData?.dependencies ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[pinnedItems]="inputData?.pinnedItems ?? []"
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
</mat-card>
<mat-card class="properties-view">
<properties-view
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
></properties-view>
</mat-card>
</div>
`,
styles: [
`
@import 'https://fonts.googleapis.com/icon?family=Material+Icons';
:root {
--default-border: #DADCE0;
}
mat-icon {
margin: 5px
}
.icon-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
viewer-input-method {
font-family: Arial, Helvetica, sans-serif;
}
.header-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
.card-grid {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
overflow: auto;
}
.hierarchy-view {
font: inherit;
margin: 0px;
width: 50%;
height: 52.5rem;
border-radius: 0;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
border-left: 1px solid var(--default-border);
}
.properties-view {
font: inherit;
margin: 0px;
width: 50%;
height: 52.5rem;
border-radius: 0;
border-top: 1px solid var(--default-border);
border-left: 1px solid var(--default-border);
}
`,
]
})
export class ViewerInputMethodComponent {
@Input() inputData: ImeUiData | null = null;
@Input() store: PersistentStore = new PersistentStore();
@Input() active = false;
TRACE_INFO = TRACE_INFO;
TraceType = TraceType;
}

View File

@@ -17,11 +17,17 @@ import { TraceType } from "common/trace/trace_type";
import { Viewer } from "./viewer";
import { ViewerWindowManager } from "./viewer_window_manager/viewer_window_manager";
import { ViewerSurfaceFlinger } from "./viewer_surface_flinger/viewer_surface_flinger";
import { ViewerInputMethodClients } from "./viewer_input_method_clients/viewer_input_method_clients";
import { ViewerInputMethodService } from "./viewer_input_method_service/viewer_input_method_service";
import { ViewerInputMethodManagerService } from "./viewer_input_method_manager_service/viewer_input_method_manager_service";
class ViewerFactory {
static readonly VIEWERS = [
ViewerWindowManager,
ViewerSurfaceFlinger
ViewerSurfaceFlinger,
ViewerInputMethodClients,
ViewerInputMethodService,
ViewerInputMethodManagerService,
];
public createViewers(activeTraceTypes: Set<TraceType>): Viewer[] {
@@ -31,6 +37,7 @@ class ViewerFactory {
const areViewerDepsSatisfied = Viewer.DEPENDENCIES.every((traceType: TraceType) =>
activeTraceTypes.has(traceType)
);
if (areViewerDepsSatisfied) {
viewers.push(new Viewer());
}

View File

@@ -0,0 +1,31 @@
/*
* 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 { ViewerInputMethod } from "viewers/common/viewer_input_method";
class ViewerInputMethodClients extends ViewerInputMethod {
public override getTitle(): string {
return "Input Method Clients";
}
public override getDependencies(): TraceType[] {
return ViewerInputMethodClients.DEPENDENCIES;
}
public static override readonly DEPENDENCIES: TraceType[] = [TraceType.INPUT_METHOD_CLIENTS];
}
export {ViewerInputMethodClients};

View File

@@ -0,0 +1,31 @@
/*
* 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 { ViewerInputMethod } from "viewers/common/viewer_input_method";
class ViewerInputMethodManagerService extends ViewerInputMethod {
public override getTitle(): string {
return "Input Method Manager Service";
}
public override getDependencies(): TraceType[] {
return ViewerInputMethodManagerService.DEPENDENCIES;
}
public static override readonly DEPENDENCIES: TraceType[] = [TraceType.INPUT_METHOD_MANAGER_SERVICE];
}
export {ViewerInputMethodManagerService};

View File

@@ -0,0 +1,31 @@
/*
* 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 { ViewerInputMethod } from "viewers/common/viewer_input_method";
class ViewerInputMethodService extends ViewerInputMethod {
public override getTitle(): string {
return "Input Method Service";
}
public override getDependencies(): TraceType[] {
return ViewerInputMethodService.DEPENDENCIES;
}
public static override readonly DEPENDENCIES: TraceType[] = [TraceType.INPUT_METHOD_SERVICE];
}
export {ViewerInputMethodService};

View File

@@ -29,7 +29,7 @@ type NotifyViewCallbackType = (uiData: UiData) => void;
export class Presenter {
constructor(notifyViewCallback: NotifyViewCallbackType) {
this.notifyViewCallback = notifyViewCallback;
this.uiData = new UiData();
this.uiData = new UiData([TraceType.SURFACE_FLINGER]);
this.notifyViewCallback(this.uiData);
}

View File

@@ -20,7 +20,7 @@ import { TraceType } from "common/trace/trace_type";
import { Rectangle } from "viewers/common/rectangle";
export class UiData {
dependencies: Array<TraceType> = [TraceType.SURFACE_FLINGER];
dependencies: Array<TraceType>;
rects: Rectangle[] = [];
displayIds: number[] = [];
hasVirtualDisplays = false;
@@ -31,4 +31,8 @@ export class UiData {
tree: HierarchyTreeNode | null = null;
propertiesTree: PropertiesTreeNode | null = null;
selectedLayer: Layer = {};
constructor(dependencies?: Array<TraceType>) {
this.dependencies = dependencies ?? [];
}
}

View File

@@ -52,6 +52,7 @@ import { PersistentStore } from "common/persistent_store";
[propertiesTree]="inputData?.propertiesTree ?? {}"
[selectedFlickerItem]="inputData?.selectedLayer ?? {}"
[propertyGroups]="true"
[isProtoDump]="true"
></properties-view>
</mat-card>
</div>

View File

@@ -29,7 +29,7 @@ type NotifyViewCallbackType = (uiData: UiData) => void;
export class Presenter {
constructor(notifyViewCallback: NotifyViewCallbackType) {
this.notifyViewCallback = notifyViewCallback;
this.uiData = new UiData();
this.uiData = new UiData([TraceType.WINDOW_MANAGER]);
this.notifyViewCallback(this.uiData);
}

View File

@@ -19,7 +19,7 @@ import { TraceType } from "common/trace/trace_type";
import { Rectangle } from "viewers/common/rectangle";
export class UiData {
dependencies: Array<TraceType> = [TraceType.WINDOW_MANAGER];
dependencies: Array<TraceType>;
rects: Rectangle[] = [];
displayIds: number[] = [];
highlightedItems: Array<string> = [];
@@ -28,4 +28,8 @@ export class UiData {
propertiesUserOptions: UserOptions = {};
tree: HierarchyTreeNode | null = null;
propertiesTree: PropertiesTreeNode | null = null;
constructor(dependencies?: Array<TraceType>) {
this.dependencies = dependencies ?? [];
}
}

View File

@@ -49,6 +49,7 @@ import { PersistentStore } from "common/persistent_store";
<properties-view
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
[isProtoDump]="true"
></properties-view>
</mat-card>
</div>