IME Viewers - Table of IME properties and SF/WM.
Add extra properties to IME viewers from the IME traces and SF/WM traces. Bug: b/238088679 Test: npm run test:all Change-Id: I177fc7353f963cc8b1391a88d5d8f4b2e4f387fa
This commit is contained in:
@@ -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]
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
) {}
|
||||
}
|
||||
@@ -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<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);
|
||||
});
|
||||
});
|
||||
@@ -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<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);
|
||||
});
|
||||
});
|
||||
@@ -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<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);
|
||||
});
|
||||
});
|
||||
@@ -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<TraceType>;
|
||||
@@ -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<TraceType>) {
|
||||
this.dependencies = dependencies ?? [];
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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<TraceType>
|
||||
@@ -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<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();
|
||||
}
|
||||
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<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 = {
|
||||
|
||||
readonly notifyViewCallback: NotifyImeViewCallbackType;
|
||||
protected readonly dependencies: Array<TraceType>;
|
||||
protected uiData: ImeUiData;
|
||||
protected highlightedItems: Array<string> = [];
|
||||
protected entry: TraceTreeNode | null = null;
|
||||
protected additionalPropertyEntry: TraceTreeNode | null = null;
|
||||
protected hierarchyUserOptions: UserOptions = {
|
||||
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;
|
||||
}
|
||||
@@ -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<TraceType, any>;
|
||||
let selectedTree: HierarchyTreeNode;
|
||||
|
||||
beforeAll(async () => {
|
||||
const entry = await getEntry();
|
||||
entries = new Map<TraceType, any>();
|
||||
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<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(expectedChildren[0]);
|
||||
presenter.filterPropertiesTree(propertiesTreeFilterString);
|
||||
|
||||
nonTerminalChildren = uiData.propertiesTree?.children?.filter(
|
||||
(child: PropertiesTreeNode) => typeof child.propertyKey === "string"
|
||||
) ?? [];
|
||||
expect(nonTerminalChildren.length).toEqual(expectedChildren[1]);
|
||||
});
|
||||
});
|
||||
}
|
||||
18
tools/winscope-ng/src/viewers/common/table_properties.ts
Normal file
18
tools/winscope-ng/src/viewers/common/table_properties.ts
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,5 +20,6 @@ export const ViewerEvents = {
|
||||
HierarchyFilterChange: "HierarchyFilterChange",
|
||||
SelectedTreeChange: "SelectedTreeChange",
|
||||
PropertiesUserOptionsChange: "PropertiesUserOptionsChange",
|
||||
PropertiesFilterChange: "PropertiesFilterChange"
|
||||
PropertiesFilterChange: "PropertiesFilterChange",
|
||||
AdditionalPropertySelected: "AdditionalPropertySelected"
|
||||
};
|
||||
|
||||
@@ -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<TraceType, any>): 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};
|
||||
|
||||
@@ -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<CoordinatesTableComponent>;
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -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: `
|
||||
<span class="coord-null-value" *ngIf="!hasCoordinates()">null</span>
|
||||
<div class="coord-table-wrapper" *ngIf="hasCoordinates()">
|
||||
<table class="table">
|
||||
<tr class="header-row">
|
||||
<td>Left</td>
|
||||
<td>Top</td>
|
||||
<td>Right</td>
|
||||
<td>Bottom</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ coordinates.left }}</td>
|
||||
<td>{{ coordinates.top }}</td>
|
||||
<td>{{ coordinates.right }}</td>
|
||||
<td>{{ coordinates.bottom }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
`,
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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}}</mat-checkbox>
|
||||
</div>
|
||||
<properties-table
|
||||
*ngIf="tableProperties"
|
||||
class="properties-table"
|
||||
[properties]="tableProperties"
|
||||
></properties-table>
|
||||
<div class="pinned-items" *ngIf="pinnedItems.length > 0">
|
||||
<tree-node
|
||||
*ngFor="let pinnedItem of pinnedItems"
|
||||
@@ -133,6 +139,13 @@ import { TraceType } from "common/trace/trace_type";
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.properties-table {
|
||||
padding-top: 5px;
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pinned-items {
|
||||
border: 2px solid yellow;
|
||||
position: relative;
|
||||
@@ -151,6 +164,7 @@ export class HierarchyComponent {
|
||||
isHighlighted = UiTreeUtils.isHighlighted;
|
||||
|
||||
@Input() tree!: HierarchyTreeNode | null;
|
||||
@Input() tableProperties?: TableProperties | null;
|
||||
@Input() dependencies: Array<TraceType> = [];
|
||||
@Input() highlightedItems: Array<string> = [];
|
||||
@Input() pinnedItems: Array<HierarchyTreeNode> = [];
|
||||
@@ -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`
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ImeAdditionalPropertiesComponent>;
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -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: `
|
||||
<mat-card-header class="view-header">
|
||||
<div class="title-filter">
|
||||
<span class="additional-properties-title">WM & SF Properties</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="additional-properties-content">
|
||||
<div *ngIf="isAllPropertiesNull()" class="group">
|
||||
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.
|
||||
</div>
|
||||
|
||||
<div *ngIf="isImeManagerService">
|
||||
<div class="group">
|
||||
<button
|
||||
class="text-button group-header"
|
||||
*ngIf="wmProtoOrNull()"
|
||||
[class]="{ 'selected': isHighlighted(wmProtoOrNull()) }"
|
||||
(click)="onClickShowInPropertiesPanel(wmProtoOrNull(), additionalProperties.wm?.name)">
|
||||
WMState
|
||||
</button>
|
||||
<span class="group-header" *ngIf="!wmProtoOrNull()">WMState</span>
|
||||
<div class="full-width">
|
||||
<span class="value" *ngIf="additionalProperties.wm">{{
|
||||
additionalProperties.wm.name }}</span>
|
||||
<span *ngIf="!additionalProperties.wm">There is no corresponding WMState entry.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group" *ngIf="wmInsetsSourceProviderOrNull()">
|
||||
<button
|
||||
class="text-button group-header"
|
||||
[class]="{ 'selected': isHighlighted(wmInsetsSourceProviderOrNull()) }"
|
||||
(click)="onClickShowInPropertiesPanel(wmInsetsSourceProviderOrNull(), 'Ime Insets Source Provider')">
|
||||
IME Insets Source Provider
|
||||
</button>
|
||||
<div class="full-width">
|
||||
<div></div>
|
||||
<span class="key">Source Frame:</span>
|
||||
<coordinates-table
|
||||
[coordinates]="wmInsetsSourceProviderSourceFrameOrNull()"
|
||||
></coordinates-table>
|
||||
<div></div>
|
||||
<span class="key">Source Visible:</span>
|
||||
<span class="value">{{
|
||||
wmInsetsSourceProviderSourceVisibleOrNull() }}</span>
|
||||
<div></div>
|
||||
<span class="key">Source Visible Frame:</span>
|
||||
<coordinates-table
|
||||
[coordinates]="wmInsetsSourceProviderSourceVisibleFrameOrNull()"
|
||||
></coordinates-table>
|
||||
<div></div>
|
||||
<span class="key">Position:</span>
|
||||
<span class="value">{{ wmInsetsSourceProviderPositionOrNull() }}</span>
|
||||
<div></div>
|
||||
<span class="key">IsLeashReadyForDispatching:</span>
|
||||
<span class="value">{{
|
||||
wmInsetsSourceProviderIsLeashReadyOrNull() }}</span>
|
||||
<div></div>
|
||||
<span class="key">Controllable:</span>
|
||||
<span class="value">{{
|
||||
wmInsetsSourceProviderControllableOrNull() }}</span>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group" *ngIf="wmImeControlTargetOrNull()">
|
||||
<button
|
||||
class="text-button group-header"
|
||||
[class]="{ 'selected': isHighlighted(wmImeControlTargetOrNull()) }"
|
||||
(click)="onClickShowInPropertiesPanel(wmImeControlTargetOrNull(), 'Ime Control Target')">
|
||||
IME Control Target
|
||||
</button>
|
||||
<div class="full-width">
|
||||
<span class="key" *ngIf="wmImeControlTargetTitleOrNull()">Title:</span>
|
||||
<span class="value" *ngIf="wmImeControlTargetTitleOrNull()">{{
|
||||
wmImeControlTargetTitleOrNull() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group" *ngIf="wmImeInputTargetOrNull()">
|
||||
<button
|
||||
class="text-button group-header"
|
||||
[class]="{ 'selected': isHighlighted(wmImeInputTargetOrNull()) }"
|
||||
(click)="onClickShowInPropertiesPanel(wmImeInputTargetOrNull(), 'Ime Input Target')">
|
||||
IME Input Target
|
||||
</button>
|
||||
<div class="full-width">
|
||||
<span class="key" *ngIf="wmImeInputTargetTitleOrNull()">Title:</span>
|
||||
<span class="value" *ngIf="wmImeInputTargetTitleOrNull()">{{
|
||||
wmImeInputTargetTitleOrNull() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group" *ngIf="wmImeLayeringTargetOrNull()">
|
||||
<button
|
||||
class="text-button group-header"
|
||||
[class]="{ 'selected': isHighlighted(wmImeLayeringTargetOrNull()) }"
|
||||
(click)="onClickShowInPropertiesPanel(wmImeLayeringTargetOrNull(), 'Ime Layering Target')">
|
||||
IME Layering Target
|
||||
</button>
|
||||
<div class="full-width">
|
||||
<span class="key" *ngIf="wmImeLayeringTargetTitleOrNull()">Title:</span>
|
||||
<span class="value" *ngIf="wmImeLayeringTargetTitleOrNull()">{{
|
||||
wmImeLayeringTargetTitleOrNull() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!isImeManagerService">
|
||||
<!-- Ime Client or Ime Service -->
|
||||
<div class="group">
|
||||
<button
|
||||
class="text-button group-header"
|
||||
*ngIf="wmProtoOrNull()"
|
||||
[class]="{ 'selected': isHighlighted(wmProtoOrNull()) }"
|
||||
(click)="onClickShowInPropertiesPanel(wmProtoOrNull(), additionalProperties.wm?.name)">
|
||||
WMState
|
||||
</button>
|
||||
<span class="group-header" *ngIf="!wmProtoOrNull()">WMState</span>
|
||||
<div class="full-width">
|
||||
<span class="value" *ngIf="additionalProperties.wm">{{
|
||||
additionalProperties.wm.name }}</span>
|
||||
<span *ngIf="!additionalProperties.wm">There is no corresponding WMState entry.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group">
|
||||
<span class="group-header">SFLayer</span>
|
||||
<div class="full-width">
|
||||
<span class="value" *ngIf="additionalProperties.sf">{{
|
||||
additionalProperties.sf.name }}</span>
|
||||
<span *ngIf="!additionalProperties.sf">There is no corresponding SFLayer entry.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group" *ngIf="additionalProperties.wm">
|
||||
<span class="group-header">Focus</span>
|
||||
<div class="full-width">
|
||||
<span class="key">Focused App:</span>
|
||||
<span class="value">{{ additionalProperties.wm.focusedApp }}</span>
|
||||
<div></div>
|
||||
<span class="key">Focused Activity:</span>
|
||||
<span class="value">{{ additionalProperties.wm.focusedActivity }}</span>
|
||||
<div></div>
|
||||
<span class="key">Focused Window:</span>
|
||||
<span class="value">{{ additionalProperties.wm.focusedWindow }}</span>
|
||||
<div></div>
|
||||
<span class="key" *ngIf="additionalProperties.sf">Focused Window Color:</span>
|
||||
<span class="value" *ngIf="additionalProperties.sf">{{
|
||||
additionalProperties.sf.focusedWindow.color
|
||||
}}</span>
|
||||
<div></div>
|
||||
<span class="key">Input Control Target Frame:</span>
|
||||
<coordinates-table
|
||||
[coordinates]="wmControlTargetFrameOrNull()"
|
||||
></coordinates-table>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group">
|
||||
<span class="group-header">Visibility</span>
|
||||
<div class="full-width">
|
||||
<span class="key" *ngIf="additionalProperties.wm">InputMethod Window:</span>
|
||||
<span class="value" *ngIf="additionalProperties.wm">{{
|
||||
additionalProperties.wm.isInputMethodWindowVisible
|
||||
}}</span>
|
||||
<div></div>
|
||||
<span class="key" *ngIf="additionalProperties.sf">InputMethod Surface:</span>
|
||||
<span class="value" *ngIf="additionalProperties.sf">{{
|
||||
additionalProperties.sf.inputMethodSurface.isInputMethodSurfaceVisible }}</span>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group" *ngIf="additionalProperties.sf">
|
||||
<button
|
||||
class="text-button group-header"
|
||||
[class]="{ 'selected': isHighlighted(additionalProperties.sf.imeContainer) }"
|
||||
(click)="onClickShowInPropertiesPanel(additionalProperties.sf.imeContainer)">
|
||||
Ime Container
|
||||
</button>
|
||||
<div class="full-width">
|
||||
<span class="key">ZOrderRelativeOfId:</span>
|
||||
<span class="value">{{
|
||||
additionalProperties.sf.imeContainer.zOrderRelativeOfId
|
||||
}}</span>
|
||||
<div></div>
|
||||
<span class="key">Z:</span>
|
||||
<span class="value">{{ additionalProperties.sf.imeContainer.z }}</span>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group" *ngIf="additionalProperties.sf">
|
||||
<button
|
||||
class="text-button group-header"
|
||||
[class]="{
|
||||
'selected': isHighlighted(additionalProperties.sf.inputMethodSurface)
|
||||
}"
|
||||
(click)="onClickShowInPropertiesPanel(
|
||||
additionalProperties.sf.inputMethodSurface)">
|
||||
Input Method Surface
|
||||
</button>
|
||||
<div class="full-width">
|
||||
<span class="key">ScreenBounds:</span>
|
||||
<coordinates-table
|
||||
[coordinates]="sfImeContainerScreenBoundsOrNull()"
|
||||
></coordinates-table>
|
||||
<div></div>
|
||||
<span class="key">Rect:</span>
|
||||
<coordinates-table
|
||||
[coordinates]="sfImeContainerRectOrNull()"
|
||||
></coordinates-table>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
`,
|
||||
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<string> = [];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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<PropertiesTableComponent>;
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -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: `
|
||||
<div class="properties-table-wrapper">
|
||||
<table class="table">
|
||||
<tr *ngFor="let entry of objectEntries(properties)">
|
||||
<td class="table-cell-name">
|
||||
<span>{{ entry[0] }}</span>
|
||||
</td>
|
||||
<td class="table-cell-value">
|
||||
<span>{{ entry[1] != undefined ? entry[1] : 'undefined' }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
`,
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -26,16 +26,24 @@ import { ImeUiData } from "viewers/common/ime_ui_data";
|
||||
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>
|
||||
<div class="left-views">
|
||||
<mat-card class="hierarchy-view" [style]="hierarchyHeight()">
|
||||
<hierarchy-view
|
||||
[tree]="inputData?.tree ?? null"
|
||||
[dependencies]="inputData?.dependencies ?? []"
|
||||
[highlightedItems]="inputData?.highlightedItems ?? []"
|
||||
[pinnedItems]="inputData?.pinnedItems ?? []"
|
||||
[tableProperties]="inputData?.hierarchyTableProperties"
|
||||
[store]="store"
|
||||
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
|
||||
></hierarchy-view>
|
||||
</mat-card>
|
||||
<mat-card *ngIf="inputData?.additionalProperties" class="ime-additional-properties-view">
|
||||
<ime-additional-properties
|
||||
[additionalProperties]="inputData?.additionalProperties!"
|
||||
></ime-additional-properties>
|
||||
</mat-card>
|
||||
</div>
|
||||
<mat-card class="properties-view">
|
||||
<properties-view
|
||||
[userOptions]="inputData?.propertiesUserOptions ?? {}"
|
||||
@@ -62,10 +70,6 @@ import { ImeUiData } from "viewers/common/ime_ui_data";
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
viewer-input-method {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.header-button {
|
||||
background: none;
|
||||
border: none;
|
||||
@@ -81,15 +85,27 @@ import { ImeUiData } from "viewers/common/ime_ui_data";
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.hierarchy-view {
|
||||
.left-views {
|
||||
font: inherit;
|
||||
margin: 0px;
|
||||
width: 50%;
|
||||
height: 52.5rem;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.hierarchy-view, .ime-additional-properties-view {
|
||||
font: inherit;
|
||||
margin: 0px;
|
||||
border-radius: 0;
|
||||
border-top: 1px solid var(--default-border);
|
||||
border-right: 1px solid var(--default-border);
|
||||
border-left: 1px solid var(--default-border);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.ime-additional-properties-view {
|
||||
height: 404px;
|
||||
}
|
||||
|
||||
.properties-view {
|
||||
@@ -100,6 +116,7 @@ import { ImeUiData } from "viewers/common/ime_ui_data";
|
||||
border-radius: 0;
|
||||
border-top: 1px solid var(--default-border);
|
||||
border-left: 1px solid var(--default-border);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
`,
|
||||
]
|
||||
@@ -110,4 +127,10 @@ export class ViewerInputMethodComponent {
|
||||
@Input() active = false;
|
||||
TRACE_INFO = TRACE_INFO;
|
||||
TraceType = TraceType;
|
||||
|
||||
public hierarchyHeight() {
|
||||
return {
|
||||
height: `${this.inputData?.additionalProperties ? 404 : 840}px`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 { PresenterInputMethodClients } from "./presenter_input_method_clients";
|
||||
import { executePresenterInputMethodTests } from "viewers/common/presenter_input_method_test_utils";
|
||||
import { UnitTestUtils } from "test/unit/utils";
|
||||
|
||||
describe("PresenterInputMethodClients", () => {
|
||||
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,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -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,
|
||||
) {}
|
||||
}
|
||||
@@ -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};
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -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,
|
||||
) {}
|
||||
}
|
||||
@@ -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};
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -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
|
||||
) {}
|
||||
}
|
||||
@@ -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};
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user