Refactor WM transformations to use flickerlib object representation
Test: Run winscope and make sure there are no errors and everything seems to still work... Change-Id: I1aef5c469d4323af502580e03a310d76da739d4d
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
"@babel/preset-env": "^7.10.4",
|
||||
"@babel/register": "^7.10.5",
|
||||
"@jetbrains/kotlin-webpack-plugin": "^3.0.2",
|
||||
"@types/lodash": "^4.14.158",
|
||||
"babel-loader": "^8.1.0",
|
||||
"compression-webpack-plugin": "^4.0.0",
|
||||
"cross-env": "^7.0.2",
|
||||
@@ -47,6 +48,8 @@
|
||||
"protobufjs": "^6.10.0",
|
||||
"source-map-loader": "^1.0.1",
|
||||
"style-loader": "^1.2.1",
|
||||
"ts-loader": "^8.0.1",
|
||||
"typescript": "^3.9.7",
|
||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||
"vue-loader": "^15.9.3",
|
||||
"vue-style-loader": "^4.1.2",
|
||||
|
||||
@@ -35,6 +35,13 @@
|
||||
:title="c.long"
|
||||
:class="chipClassForChip(c)"
|
||||
>{{c.short}} <!-- No line break on purpose -->
|
||||
<md-tooltip
|
||||
md-delay="300"
|
||||
md-direction="top"
|
||||
style="margin-bottom: -10px"
|
||||
>
|
||||
{{c.long}}
|
||||
</md-tooltip>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<template>
|
||||
<div class="bounds" :style="boundsStyle">
|
||||
<div
|
||||
class="rect" v-for="r in rects"
|
||||
class="rect" v-for="r in filteredRects"
|
||||
:style="rectToStyle(r)"
|
||||
@click="onClick(r)"
|
||||
v-bind:key="`${r.left}-${r.right}-${r.top}-${r.bottom}-${r.ref.name}`"
|
||||
@@ -55,6 +55,9 @@ export default {
|
||||
return this.rectToStyle({top: 0, left: 0, right: this.boundsC.width,
|
||||
bottom: this.boundsC.height});
|
||||
},
|
||||
filteredRects() {
|
||||
return this.rects.filter((rect) => rect.ref.visible);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
s(sourceCoordinate) { // translate source into target coordinates
|
||||
|
||||
@@ -209,7 +209,7 @@ export default {
|
||||
itemSelected(item) {
|
||||
this.hierarchySelected = item;
|
||||
this.selectedTree = this.getTransformedProperties(item);
|
||||
this.highlight = item.highlight;
|
||||
this.highlight = item.rect;
|
||||
this.lastSelectedStableId = item.stableId;
|
||||
this.$emit('focus');
|
||||
},
|
||||
|
||||
@@ -26,7 +26,6 @@ import jsonProtoDefsSysUi from 'frameworks/base/packages/SystemUI/src/com/androi
|
||||
import jsonProtoDefsLauncher from 'packages/apps/Launcher3/protos/launcher_trace_file.proto';
|
||||
import protobuf from 'protobufjs';
|
||||
import {transformLayers, transformLayersTrace} from './transform_sf.js';
|
||||
import {transform_window_service, transform_window_trace} from './transform_wm.js';
|
||||
import {transform_transaction_trace} from './transform_transaction.js';
|
||||
import {transform_wl_outputstate, transform_wayland_trace} from './transform_wl.js';
|
||||
import {transformProtolog} from './transform_protolog.js';
|
||||
@@ -211,7 +210,7 @@ const FILE_DECODERS = {
|
||||
decoderParams: {
|
||||
type: FILE_TYPES.WINDOW_MANAGER_TRACE,
|
||||
protoType: WmTraceMessage,
|
||||
transform: transform_window_trace,
|
||||
transform: WindowManagerTrace.fromProto,
|
||||
timeline: true,
|
||||
},
|
||||
},
|
||||
@@ -255,7 +254,7 @@ const FILE_DECODERS = {
|
||||
type: FILE_TYPES.WINDOW_MANAGER_DUMP,
|
||||
mime: 'application/octet-stream',
|
||||
protoType: WmDumpMessage,
|
||||
transform: transform_window_service,
|
||||
transform: WindowManagerDump.fromProto,
|
||||
timeline: false,
|
||||
},
|
||||
},
|
||||
@@ -380,7 +379,7 @@ function protoDecoder(buffer, params, fileName, store) {
|
||||
const transformed = decodeAndTransformProto(buffer, params, store.displayDefaults);
|
||||
let data;
|
||||
if (params.timeline) {
|
||||
data = transformed.children;
|
||||
data = transformed.entries ?? transformed.children;
|
||||
} else {
|
||||
data = [transformed];
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
import { FILE_TYPES, DUMP_TYPES } from "@/decode.js";
|
||||
import DumpBase from "./DumpBase";
|
||||
|
||||
import { WindowManagerTraceEntry } from '@/flickerlib';
|
||||
|
||||
export default class WindowManager extends DumpBase {
|
||||
wmDumpFile: any;
|
||||
|
||||
@@ -29,4 +31,8 @@ export default class WindowManager extends DumpBase {
|
||||
get type() {
|
||||
return DUMP_TYPES.WINDOW_MANAGER;
|
||||
}
|
||||
|
||||
static fromProto(proto): WindowManagerTraceEntry {
|
||||
return WindowManagerTraceEntry.fromProto(proto);
|
||||
}
|
||||
}
|
||||
12
tools/winscope/src/flickerlib/README.md
Normal file
12
tools/winscope/src/flickerlib/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
This directory contains all the code extending the common Flicker library
|
||||
to make it fully compatible with Winscope. The common Flicker library is
|
||||
written is Kotlin and compiled to JavaScript and then extended by the code in
|
||||
this directory.
|
||||
|
||||
To use flickerlib in the rest of the Winscope source code use
|
||||
`import { ... } from '@/flickerlib'` rather than importing the compiled
|
||||
common Flicker library directly.
|
||||
|
||||
The flickerlib classes are extended through mixins (functions, getter, and
|
||||
setters) that are injected into the original compiled common Flicker library
|
||||
classes.
|
||||
36
tools/winscope/src/flickerlib/WindowManagerTrace.ts
Normal file
36
tools/winscope/src/flickerlib/WindowManagerTrace.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2020, 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 {
|
||||
WindowManagerTrace,
|
||||
} from "./common"
|
||||
|
||||
import WindowManagerTraceEntry from "./WindowManagerTraceEntry"
|
||||
|
||||
WindowManagerTrace.fromProto = function (proto) {
|
||||
const entries = []
|
||||
for (const entryProto of proto.entry) {
|
||||
const transformedEntry = WindowManagerTraceEntry.fromProto(
|
||||
entryProto.windowManagerService, entryProto.elapsedRealtimeNanos)
|
||||
entries.push(transformedEntry)
|
||||
}
|
||||
|
||||
const source = null;
|
||||
const sourceChecksum = null;
|
||||
return new WindowManagerTrace(entries, source, sourceChecksum)
|
||||
}
|
||||
|
||||
export default WindowManagerTrace;
|
||||
113
tools/winscope/src/flickerlib/WindowManagerTraceEntry.ts
Normal file
113
tools/winscope/src/flickerlib/WindowManagerTraceEntry.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { nanosToString, TimeUnits } from "../utils/utils.js"
|
||||
|
||||
import { WindowManagerTraceEntry } from "./common"
|
||||
|
||||
import { applyMixins } from "./mixin"
|
||||
|
||||
import ITreeViewElement from './treeview/IClickableTreeViewElement'
|
||||
import IClickableTreeViewElement from './treeview/IClickableTreeViewElement'
|
||||
import Chip from './treeview/Chip'
|
||||
import WindowContainer from "./windows/WindowContainer"
|
||||
|
||||
class WindowManagerTraceEntryMixin implements IClickableTreeViewElement {
|
||||
common: any
|
||||
kind: string
|
||||
name: string
|
||||
shortName: string
|
||||
stableId: string
|
||||
chips: Array<Chip>
|
||||
children: Array<ITreeViewElement>
|
||||
obj: any
|
||||
rawTreeViewObject
|
||||
|
||||
timestamp: number
|
||||
rootWindow
|
||||
|
||||
mixinConstructor(obj) {
|
||||
const name = this.timestamp ? nanosToString(this.timestamp, TimeUnits.MILLI_SECONDS) : ""
|
||||
this.kind = "entry"
|
||||
this.name = name
|
||||
this.shortName = name
|
||||
this.stableId = "entry"
|
||||
this.children = this.rootWindow.children
|
||||
this.chips = []
|
||||
this.obj = obj
|
||||
}
|
||||
|
||||
static fromProto(proto, timestamp) {
|
||||
const rootWindow =
|
||||
WindowContainer.fromProto(proto.rootWindowContainer.windowContainer)
|
||||
const windowManagerTraceEntry =
|
||||
new WindowManagerTraceEntry(rootWindow, timestamp)
|
||||
|
||||
windowManagerTraceEntry.kind = 'service'
|
||||
|
||||
windowManagerTraceEntry.focusedApp = proto.focusedApp
|
||||
windowManagerTraceEntry.focusedDisplayId = proto.focusedDisplayId
|
||||
windowManagerTraceEntry.lastOrientation = proto.lastOrientation
|
||||
windowManagerTraceEntry.policy = proto.policy
|
||||
windowManagerTraceEntry.rotation = proto.rotation
|
||||
windowManagerTraceEntry.displayFrozen = proto.displayFrozen
|
||||
windowManagerTraceEntry.inputMethodWindow = proto.inputMethodWindow
|
||||
|
||||
// Remove anything that is part of the children elements
|
||||
// allows for faster loading of properties and less information cluttering
|
||||
// this applied to anywhere the proto is passed to be saved as .obj
|
||||
const obj = Object.assign({}, proto)
|
||||
obj.rootWindowContainer = {};
|
||||
Object.assign(obj.rootWindowContainer,
|
||||
proto.rootWindowContainer)
|
||||
obj.rootWindowContainer.windowContainer = {};
|
||||
Object.assign(obj.rootWindowContainer.windowContainer,
|
||||
proto.rootWindowContainer.windowContainer)
|
||||
delete obj.rootWindowContainer.windowContainer.children
|
||||
windowManagerTraceEntry.mixinConstructor(obj)
|
||||
|
||||
return windowManagerTraceEntry
|
||||
}
|
||||
|
||||
attachObject(obj) {
|
||||
this.obj = obj
|
||||
}
|
||||
|
||||
asRawTreeViewObject() {
|
||||
// IMPORTANT: We want to always return the same tree view object and not
|
||||
// generate a new one every time this function is called.
|
||||
if (!this.rawTreeViewObject) {
|
||||
const children = this.children.map(child => child.asRawTreeViewObject())
|
||||
|
||||
this.rawTreeViewObject = {
|
||||
kind: this.kind,
|
||||
name: this.name,
|
||||
shortName: this.shortName,
|
||||
stableId: this.stableId,
|
||||
chips: this.chips,
|
||||
obj: this.obj,
|
||||
children,
|
||||
ref: this,
|
||||
}
|
||||
}
|
||||
|
||||
return this.rawTreeViewObject;
|
||||
}
|
||||
}
|
||||
|
||||
applyMixins(WindowManagerTraceEntry, [WindowManagerTraceEntryMixin])
|
||||
|
||||
export default WindowManagerTraceEntry;
|
||||
58
tools/winscope/src/flickerlib/common.js
Normal file
58
tools/winscope/src/flickerlib/common.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2020, 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.
|
||||
*/
|
||||
|
||||
// Imports all the compiled common Flicker library classes and exports them
|
||||
// as clean es6 modules rather than having them be commonjs modules
|
||||
|
||||
const WindowManagerTrace = require('flicker').com.android.server.wm.flicker
|
||||
.common.traces.windowmanager.WindowManagerTrace;
|
||||
const WindowManagerTraceEntry = require('flicker').com.android.server.wm.
|
||||
flicker.common.traces.windowmanager.WindowManagerTraceEntry;
|
||||
|
||||
const WindowContainer = require('flicker').com.android.server.wm.flicker.common.
|
||||
traces.windowmanager.windows.WindowContainer;
|
||||
const WindowState = require('flicker').com.android.server.wm.flicker.common.
|
||||
traces.windowmanager.windows.WindowState;
|
||||
const DisplayContent = require('flicker').com.android.server.wm.flicker.common.
|
||||
traces.windowmanager.windows.DisplayContent;
|
||||
const ActivityRecord = require('flicker').com.android.server.wm.flicker.common.
|
||||
traces.windowmanager.windows.ActivityRecord;
|
||||
const WindowToken = require('flicker').com.android.server.wm.flicker.common.
|
||||
traces.windowmanager.windows.WindowToken;
|
||||
const DisplayArea = require('flicker').com.android.server.wm.flicker.common.
|
||||
traces.windowmanager.windows.DisplayArea;
|
||||
const RootDisplayArea = require('flicker').com.android.server.wm.flicker.common.
|
||||
traces.windowmanager.windows.RootDisplayArea;
|
||||
const Task = require('flicker').com.android.server.wm.flicker.common.traces.
|
||||
windowmanager.windows.Task;
|
||||
|
||||
const Rect = require('flicker').com.android.server.wm.flicker.common.Rect;
|
||||
const Bounds = require('flicker').com.android.server.wm.flicker.common.Bounds;
|
||||
|
||||
export {
|
||||
WindowManagerTrace,
|
||||
WindowManagerTraceEntry,
|
||||
WindowContainer,
|
||||
WindowState,
|
||||
DisplayContent,
|
||||
ActivityRecord,
|
||||
WindowToken,
|
||||
DisplayArea,
|
||||
RootDisplayArea,
|
||||
Task,
|
||||
Rect,
|
||||
Bounds,
|
||||
};
|
||||
25
tools/winscope/src/flickerlib/index.js
Normal file
25
tools/winscope/src/flickerlib/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2020, 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 WindowManagerTraceEntry from './WindowManagerTraceEntry';
|
||||
import WindowManagerTrace from './WindowManagerTrace';
|
||||
|
||||
/**
|
||||
* Entry point into the flickerlib for Winscope.
|
||||
* Expose everything we want Winscope to have access to here.
|
||||
*/
|
||||
export {WindowManagerTraceEntry, WindowManagerTrace};
|
||||
|
||||
23
tools/winscope/src/flickerlib/mixin.ts
Normal file
23
tools/winscope/src/flickerlib/mixin.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Injects all the properties (getters, setters, functions...) of a list of
|
||||
* classes (baseCtors) into a class (derivedCtor).
|
||||
* @param derivedCtor The constructor of the class we want to inject the
|
||||
* properties into.
|
||||
* @param baseCtors A list of consturctor of the classes we want to mixin the
|
||||
* properties of into the derivedCtor.
|
||||
*/
|
||||
export function applyMixins(derivedCtor: any, baseCtors: any[]) {
|
||||
baseCtors.forEach(baseCtor => {
|
||||
Object.getOwnPropertyNames(baseCtor).forEach(name => {
|
||||
if (['length', 'name', 'prototype'].includes(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.defineProperty(derivedCtor, name, Object.getOwnPropertyDescriptor(baseCtor, name))
|
||||
})
|
||||
|
||||
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
|
||||
Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name))
|
||||
})
|
||||
});
|
||||
}
|
||||
29
tools/winscope/src/flickerlib/treeview/Chip.ts
Normal file
29
tools/winscope/src/flickerlib/treeview/Chip.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2020, 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 ChipType from "./ChipType"
|
||||
|
||||
export default class Chip {
|
||||
short: String
|
||||
long: String
|
||||
type: ChipType
|
||||
|
||||
constructor(short: String, long: String, type: ChipType) {
|
||||
this.short = short
|
||||
this.long = long
|
||||
this.type = type
|
||||
}
|
||||
}
|
||||
21
tools/winscope/src/flickerlib/treeview/ChipType.ts
Normal file
21
tools/winscope/src/flickerlib/treeview/ChipType.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2020, 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.
|
||||
*/
|
||||
|
||||
enum ChipType {
|
||||
DEFAULT = 'default'
|
||||
}
|
||||
|
||||
export default ChipType
|
||||
20
tools/winscope/src/flickerlib/treeview/Chips.ts
Normal file
20
tools/winscope/src/flickerlib/treeview/Chips.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2020, 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 Chip from "./Chip"
|
||||
import ChipType from "./ChipType"
|
||||
|
||||
export const VISIBLE_CHIP = new Chip("V", "visible", ChipType.DEFAULT)
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2020, 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 ITreeViewElement from "./ITreeViewElement"
|
||||
|
||||
export default interface IClickableTreeViewElement extends ITreeViewElement {
|
||||
obj: any
|
||||
}
|
||||
34
tools/winscope/src/flickerlib/treeview/ITreeViewElement.ts
Normal file
34
tools/winscope/src/flickerlib/treeview/ITreeViewElement.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2020, 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 Chip from "./Chip"
|
||||
import { TreeViewObject } from "./types"
|
||||
|
||||
export default interface ITreeViewElement {
|
||||
kind: String
|
||||
name: String
|
||||
shortName: String
|
||||
stableId: Number | String
|
||||
chips: Chip[]
|
||||
children: ITreeViewElement[]
|
||||
|
||||
// This is used for compatibility with the "legacy" Winscope infrastructure
|
||||
// where a class object would cause things to not work properly so this should
|
||||
// return a raw javascript object with the relevant information.
|
||||
// IMPORTANT: The implementation of this function should always return the
|
||||
// same object every time it is called and not generate a new object.
|
||||
asRawTreeViewObject(): TreeViewObject
|
||||
}
|
||||
12
tools/winscope/src/flickerlib/treeview/types.ts
Normal file
12
tools/winscope/src/flickerlib/treeview/types.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import Chip from './Chip'
|
||||
|
||||
export type TreeViewObject = {
|
||||
kind: String
|
||||
name: String
|
||||
shortName: String
|
||||
stableId: String | Number
|
||||
chips: Chip[]
|
||||
obj: any
|
||||
children: TreeViewObject[]
|
||||
ref: any
|
||||
}
|
||||
46
tools/winscope/src/flickerlib/windows/ActivityRecord.ts
Normal file
46
tools/winscope/src/flickerlib/windows/ActivityRecord.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2020, 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 {
|
||||
ActivityRecord,
|
||||
} from "../common"
|
||||
|
||||
import { applyMixins } from '../mixin'
|
||||
|
||||
import WindowToken from "./WindowToken"
|
||||
|
||||
export class ActivityRecordMixin {
|
||||
get kind() {
|
||||
return "DisplayArea"
|
||||
}
|
||||
|
||||
static fromProto(proto) {
|
||||
const windowToken = WindowToken.fromProto(proto.windowToken)
|
||||
|
||||
const activityRecord = new ActivityRecord(windowToken)
|
||||
|
||||
const obj = Object.assign({}, proto)
|
||||
delete proto.windowToken
|
||||
Object.assign(obj, windowToken.obj)
|
||||
activityRecord.attachObject(obj)
|
||||
|
||||
return activityRecord
|
||||
}
|
||||
}
|
||||
|
||||
applyMixins(ActivityRecord, [ActivityRecordMixin])
|
||||
|
||||
export default ActivityRecord
|
||||
46
tools/winscope/src/flickerlib/windows/DisplayArea.ts
Normal file
46
tools/winscope/src/flickerlib/windows/DisplayArea.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2020, 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 {
|
||||
DisplayArea,
|
||||
} from "../common"
|
||||
|
||||
import { applyMixins } from '../mixin'
|
||||
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
export class DisplayAreaMixin {
|
||||
get kind() {
|
||||
return "DisplayArea"
|
||||
}
|
||||
|
||||
static fromProto(proto) {
|
||||
const windowContainer = WindowContainer.fromProto(proto.windowContainer)
|
||||
|
||||
const displayArea = new DisplayArea(windowContainer)
|
||||
|
||||
const obj = Object.assign({}, proto)
|
||||
delete obj.windowContainer
|
||||
Object.assign(obj, windowContainer.obj)
|
||||
displayArea.attachObject(obj)
|
||||
|
||||
return displayArea
|
||||
}
|
||||
}
|
||||
|
||||
applyMixins(DisplayArea, [DisplayAreaMixin])
|
||||
|
||||
export default DisplayArea
|
||||
62
tools/winscope/src/flickerlib/windows/DisplayContent.ts
Normal file
62
tools/winscope/src/flickerlib/windows/DisplayContent.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2020, 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 {
|
||||
DisplayContent,
|
||||
Bounds
|
||||
} from "../common"
|
||||
|
||||
import { applyMixins } from '../mixin'
|
||||
|
||||
import WindowContainer from "./WindowContainer"
|
||||
import DisplayArea from "./DisplayArea"
|
||||
|
||||
export class DisplayContentMixin {
|
||||
get kind() {
|
||||
return "DisplayContent"
|
||||
}
|
||||
|
||||
static fromProto(proto) {
|
||||
let rootDisplayArea;
|
||||
if (proto.rootDisplayArea.windowContainer == null) {
|
||||
// For backward compatibility
|
||||
const windowContainer = WindowContainer.fromProto(proto.windowContainer)
|
||||
rootDisplayArea = new DisplayArea(windowContainer)
|
||||
} else {
|
||||
// New protos should always be using this
|
||||
rootDisplayArea = DisplayArea.fromProto(proto.rootDisplayArea)
|
||||
}
|
||||
|
||||
const bounds = new Bounds(
|
||||
proto.displayInfo.logicalWidth || 0,
|
||||
proto.displayInfo.logicalHeight || 0,
|
||||
)
|
||||
|
||||
const displayContent = new DisplayContent(rootDisplayArea, bounds)
|
||||
|
||||
const obj = Object.assign({}, proto)
|
||||
delete obj.windowContainer
|
||||
delete obj.rootDisplayArea
|
||||
Object.assign(obj, rootDisplayArea.obj)
|
||||
displayContent.attachObject(obj)
|
||||
|
||||
return displayContent
|
||||
}
|
||||
}
|
||||
|
||||
applyMixins(DisplayContent, [DisplayContentMixin])
|
||||
|
||||
export default DisplayContent
|
||||
22
tools/winscope/src/flickerlib/windows/RootDisplayArea.ts
Normal file
22
tools/winscope/src/flickerlib/windows/RootDisplayArea.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { RootDisplayArea } from "../common"
|
||||
import DisplayArea from "./DisplayArea"
|
||||
|
||||
RootDisplayArea.fromProto = DisplayArea.fromProto
|
||||
|
||||
export default DisplayArea
|
||||
44
tools/winscope/src/flickerlib/windows/Task.ts
Normal file
44
tools/winscope/src/flickerlib/windows/Task.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { Task } from "../common"
|
||||
|
||||
import { applyMixins } from '../mixin'
|
||||
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
export class TaskMixin {
|
||||
get kind() {
|
||||
return "Task"
|
||||
}
|
||||
|
||||
static fromProto(proto) {
|
||||
const windowContainer = WindowContainer.fromProto(proto.windowContainer)
|
||||
|
||||
const task = new Task(windowContainer)
|
||||
|
||||
const obj = Object.assign({}, proto)
|
||||
delete obj.windowContainer
|
||||
Object.assign(obj, windowContainer.obj)
|
||||
task.attachObject(obj)
|
||||
|
||||
return task
|
||||
}
|
||||
}
|
||||
|
||||
applyMixins(Task, [TaskMixin])
|
||||
|
||||
export default Task
|
||||
204
tools/winscope/src/flickerlib/windows/WindowContainer.ts
Normal file
204
tools/winscope/src/flickerlib/windows/WindowContainer.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { WindowContainer } from "../common"
|
||||
|
||||
import { applyMixins } from '../mixin'
|
||||
|
||||
import IClickableTreeViewElement from '../treeview/IClickableTreeViewElement'
|
||||
import { TreeViewObject } from '../treeview/types'
|
||||
|
||||
import DisplayArea from "./DisplayArea"
|
||||
import DisplayContent from "./DisplayContent"
|
||||
import Task from "./Task"
|
||||
import ActivityRecord from "./ActivityRecord"
|
||||
import WindowToken from "./WindowToken"
|
||||
import WindowState from "./WindowState"
|
||||
|
||||
import { CompatibleFeatures } from '@/utils/compatibility.js'
|
||||
|
||||
export class WindowContainerMixin implements IClickableTreeViewElement {
|
||||
title: string
|
||||
windowHashCode: number
|
||||
childrenWindows
|
||||
visible: boolean
|
||||
rawTreeViewObject
|
||||
|
||||
_obj: { name: string }
|
||||
_children
|
||||
|
||||
get kind() {
|
||||
return "WindowContainer"
|
||||
}
|
||||
|
||||
get name() {
|
||||
if (this.obj && this.obj.name) {
|
||||
return this.obj.name
|
||||
}
|
||||
|
||||
if (["WindowContainer", "Task"].includes(this.title)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return `${removeRedundancyInName(this.title)}@${this.windowHashCode}`
|
||||
}
|
||||
|
||||
get shortName() {
|
||||
return this.name ? shortenName(this.name) : null
|
||||
}
|
||||
|
||||
get stableId() {
|
||||
return this.windowHashCode
|
||||
}
|
||||
|
||||
get children() {
|
||||
return this._children ?? this.childrenWindows
|
||||
}
|
||||
|
||||
set children(children) {
|
||||
this._children = children
|
||||
}
|
||||
|
||||
get chips() {
|
||||
return []
|
||||
}
|
||||
|
||||
set obj(obj) {
|
||||
this._obj = obj
|
||||
}
|
||||
|
||||
get obj() {
|
||||
return this._obj
|
||||
}
|
||||
|
||||
static fromProto(proto) {
|
||||
const children = proto.children.map(
|
||||
child => transformWindowContainerChildProto(child))
|
||||
|
||||
// A kind of hacky way to check if the proto is from a device which
|
||||
// didn't have the changes required for the diff viewer to work properly
|
||||
// We required that all elements have a stable identifier in order to do the
|
||||
// diff properly. In theory properties diff would still work, but are
|
||||
// currently disabled. If required in the future don't hesitate to make
|
||||
// the required changes.
|
||||
if (!proto.identifier) {
|
||||
CompatibleFeatures.DiffVisualization = false;
|
||||
}
|
||||
|
||||
|
||||
const title = proto.identifier.title
|
||||
const hashCode = proto.identifier.hashCode
|
||||
const visible = proto.visible
|
||||
const windowContainer =
|
||||
new WindowContainer(children, title, hashCode, visible)
|
||||
|
||||
const obj = Object.assign({}, proto)
|
||||
// we remove the children property from the object to avoid it showing the
|
||||
// the properties view of the element as we can always see those elements'
|
||||
// properties by changing the target element in the hierarchy tree view.
|
||||
delete obj.children
|
||||
windowContainer.attachObject(obj)
|
||||
|
||||
return windowContainer
|
||||
}
|
||||
|
||||
attachObject(obj) {
|
||||
this._obj = obj
|
||||
}
|
||||
|
||||
asRawTreeViewObject(): TreeViewObject {
|
||||
// IMPORTANT: We want to always return the same tree view object and not
|
||||
// generate a new one every time this function is called.
|
||||
if (!this.rawTreeViewObject) {
|
||||
const children = this.children.map(child => child.asRawTreeViewObject())
|
||||
|
||||
this.rawTreeViewObject = {
|
||||
kind: this.kind,
|
||||
name: this.name,
|
||||
shortName: this.shortName,
|
||||
stableId: this.stableId,
|
||||
chips: this.chips,
|
||||
obj: this.obj,
|
||||
children,
|
||||
ref: this,
|
||||
};
|
||||
}
|
||||
|
||||
return this.rawTreeViewObject;
|
||||
}
|
||||
}
|
||||
|
||||
applyMixins(WindowContainer, [WindowContainerMixin])
|
||||
|
||||
function transformWindowContainerChildProto(proto) {
|
||||
if (proto.displayArea != null) {
|
||||
return DisplayArea.fromProto(proto.displayArea)
|
||||
}
|
||||
|
||||
if (proto.displayContent != null) {
|
||||
return DisplayContent.fromProto(proto.displayContent)
|
||||
}
|
||||
|
||||
if (proto.task != null) {
|
||||
return Task.fromProto(proto.task)
|
||||
}
|
||||
|
||||
if (proto.activity != null) {
|
||||
return ActivityRecord.fromProto(proto.activity)
|
||||
}
|
||||
|
||||
if (proto.windowToken != null) {
|
||||
return WindowToken.fromProto(proto.windowToken)
|
||||
}
|
||||
|
||||
if (proto.window != null) {
|
||||
return WindowState.fromProto(proto.window)
|
||||
}
|
||||
|
||||
throw new Error("Unhandled WindowContainerChildProto case...")
|
||||
}
|
||||
|
||||
function removeRedundancyInName(name: string): string {
|
||||
if (!name.includes('/')) {
|
||||
return name
|
||||
}
|
||||
|
||||
const split = name.split('/')
|
||||
const pkg = split[0]
|
||||
var clazz = split.slice(1).join("/")
|
||||
|
||||
if (clazz.startsWith("$pkg.")) {
|
||||
clazz = clazz.slice(pkg.length + 1)
|
||||
|
||||
return "$pkg/$clazz"
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
function shortenName(name: string): string {
|
||||
const classParts = name.split(".")
|
||||
|
||||
if (classParts.length <= 3) {
|
||||
return name
|
||||
}
|
||||
|
||||
const className = classParts.slice(-1)[0] // last element
|
||||
|
||||
return `${classParts[0]}.${classParts[1]}.(...).${className}`
|
||||
}
|
||||
|
||||
export default WindowContainer
|
||||
55
tools/winscope/src/flickerlib/windows/WindowState.ts
Normal file
55
tools/winscope/src/flickerlib/windows/WindowState.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { WindowState, Rect } from "../common"
|
||||
import { VISIBLE_CHIP } from '../treeview/Chips'
|
||||
|
||||
import { applyMixins } from '../mixin'
|
||||
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
export class WindowStateMixin {
|
||||
visible: boolean
|
||||
|
||||
get kind() {
|
||||
return "WindowState"
|
||||
}
|
||||
|
||||
static fromProto(proto) {
|
||||
const windowContainer = WindowContainer.fromProto(proto.windowContainer)
|
||||
|
||||
const frame = (proto.windowFrames ?? proto).frame ?? {}
|
||||
const rect = new Rect(frame.left ?? 0, frame.top ?? 0, frame.right ?? 0, frame.bottom ?? 0)
|
||||
|
||||
const windowState =
|
||||
new WindowState(windowContainer, /* childWindows */[], rect)
|
||||
|
||||
const obj = Object.assign({}, proto)
|
||||
Object.assign(obj, windowContainer.obj)
|
||||
delete obj.windowContainer
|
||||
windowState.attachObject(obj)
|
||||
|
||||
return windowState
|
||||
}
|
||||
|
||||
get chips() {
|
||||
return this.visible ? [VISIBLE_CHIP] : []
|
||||
}
|
||||
}
|
||||
|
||||
applyMixins(WindowState, [WindowStateMixin])
|
||||
|
||||
export default WindowState
|
||||
44
tools/winscope/src/flickerlib/windows/WindowToken.ts
Normal file
44
tools/winscope/src/flickerlib/windows/WindowToken.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { WindowToken } from "../common"
|
||||
|
||||
import { applyMixins } from '../mixin'
|
||||
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
export class WindowContainerMixin {
|
||||
get kind() {
|
||||
return "WindowToken"
|
||||
}
|
||||
|
||||
static fromProto(proto) {
|
||||
const windowContainer = WindowContainer.fromProto(proto.windowContainer)
|
||||
|
||||
const windowToken = new WindowToken(windowContainer)
|
||||
|
||||
const obj = Object.assign({}, proto)
|
||||
Object.assign(obj, windowContainer.obj)
|
||||
delete obj.windowContainer
|
||||
windowToken.attachObject(obj)
|
||||
|
||||
return windowToken
|
||||
}
|
||||
}
|
||||
|
||||
applyMixins(WindowToken, [WindowContainerMixin])
|
||||
|
||||
export default WindowToken
|
||||
@@ -17,6 +17,8 @@
|
||||
import { FILE_TYPES, TRACE_TYPES } from '@/decode.js';
|
||||
import TraceBase from './TraceBase';
|
||||
|
||||
import { WindowManagerTrace } from '@/flickerlib';
|
||||
|
||||
export default class WindowManager extends TraceBase {
|
||||
wmTraceFile: Object;
|
||||
|
||||
@@ -30,4 +32,8 @@ export default class WindowManager extends TraceBase {
|
||||
get type() {
|
||||
return TRACE_TYPES.WINDOW_MANAGER;
|
||||
}
|
||||
|
||||
static fromProto(proto): WindowManagerTrace {
|
||||
return WindowManagerTrace.fromProto(proto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,276 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017, 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 { transform, nanos_to_string, get_visible_chip } from './transform.js'
|
||||
import { CompatibleFeatures } from './utils/compatibility.js'
|
||||
import { getComponentClassName } from './utils/names';
|
||||
|
||||
function transform_window(entry) {
|
||||
const chips = [];
|
||||
const renderIdentifier = (id) => shortenComponentName(id.title) + "@" + id.hashCode;
|
||||
const visible = entry.windowContainer.visible;
|
||||
function transform_rect(rect, label) {
|
||||
const r = rect || {};
|
||||
return {
|
||||
left: r.left || 0,
|
||||
right: r.right || 0,
|
||||
top: r.top || 0,
|
||||
bottom: r.bottom || 0,
|
||||
label,
|
||||
}
|
||||
}
|
||||
|
||||
// For backward compatibility
|
||||
if (!entry.windowContainer?.identifier) {
|
||||
CompatibleFeatures.DiffVisualization = false;
|
||||
}
|
||||
const identifier = entry.windowContainer?.identifier ?? entry.identifier;
|
||||
const name = renderIdentifier(identifier);
|
||||
const shortName = getComponentClassName(identifier.title);
|
||||
let rect = transform_rect((entry.windowFrames || entry).frame, name);
|
||||
|
||||
if (visible) {
|
||||
chips.push(get_visible_chip());
|
||||
} else {
|
||||
rect = undefined;
|
||||
}
|
||||
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'window',
|
||||
name,
|
||||
shortName,
|
||||
stableId: entry.windowContainer?.identifier?.hashCode,
|
||||
children: [
|
||||
[entry.childWindows, transform_window],
|
||||
[entry.windowContainer.children.reverse(), transform_window_container_child],
|
||||
],
|
||||
rect,
|
||||
highlight: rect,
|
||||
chips: chips,
|
||||
visible: visible,
|
||||
});
|
||||
}
|
||||
|
||||
function transform_activity_record(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'activityRecord',
|
||||
name: entry.name,
|
||||
shortName: getComponentClassName(entry.name),
|
||||
stableId: entry.windowToken.windowContainer?.identifier?.hashCode,
|
||||
children: [
|
||||
[entry.windowToken.windows, transform_window],
|
||||
[entry.windowToken.windowContainer.children.reverse(), transform_window_container_child],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function transform_task(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'task',
|
||||
name: entry.id || 0,
|
||||
stableId: entry.windowContainer?.identifier?.hashCode,
|
||||
children: [
|
||||
[entry.tasks, transform_task],
|
||||
[entry.activities, transform_activity_record],
|
||||
[entry.windowContainer.children.reverse(), transform_window_container_child],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function transform_stack(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'stack',
|
||||
name: entry.id || 0,
|
||||
children: [
|
||||
[entry.tasks, transform_task],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function transform_window_token(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'winToken',
|
||||
name: '',
|
||||
stableId: entry.windowContainer?.identifier?.hashCode,
|
||||
children: [
|
||||
[entry.windows, transform_window],
|
||||
[entry.windowContainer.children.reverse(), transform_window_container_child],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function transform_below(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'belowAppWindow',
|
||||
name: '',
|
||||
children: [
|
||||
[entry.windows, transform_window],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function transform_above(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'aboveAppWindow',
|
||||
name: '',
|
||||
children: [
|
||||
[entry.windows, transform_window],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function transform_ime(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'imeWindow',
|
||||
name: '',
|
||||
children: [
|
||||
[entry.windows, transform_window],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function transform_window_container_child(entry) {
|
||||
if (entry.displayArea != null) { return transform_display_area(entry.displayArea) }
|
||||
if (entry.displayContent != null) { return transform_display_content(entry.displayContent) }
|
||||
if (entry.task != null) { return transform_task(entry.task) }
|
||||
if (entry.activity != null) { return transform_activity_record(entry.activity) }
|
||||
if (entry.windowToken != null) { return transform_window_token(entry.windowToken) }
|
||||
if (entry.window != null) { return transform_window(entry.window) }
|
||||
|
||||
// The WindowContainerChild may be unknown
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'WindowContainerChild',
|
||||
name: '',
|
||||
stableId: entry.windowContainer?.identifier?.hashCode,
|
||||
children: [[entry.windowContainer.children.reverse(), transform_window_container_child],]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function transform_display_area(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'DisplayArea',
|
||||
name: entry.name,
|
||||
stableId: entry.windowContainer?.identifier?.hashCode,
|
||||
children: [
|
||||
[entry.windowContainer.children.reverse(), transform_window_container_child],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function transform_display_content(entry) {
|
||||
var bounds = {
|
||||
width: entry.displayInfo.logicalWidth || 0,
|
||||
height: entry.displayInfo.logicalHeight || 0,
|
||||
};
|
||||
var children = entry.windowContainer == null
|
||||
? entry.rootDisplayArea.windowContainer.children.reverse()
|
||||
: entry.windowContainer.children.reverse();
|
||||
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'display',
|
||||
name: entry.id || 0,
|
||||
stableId: entry.windowContainer?.identifier?.hashCode,
|
||||
children: [
|
||||
[entry.aboveAppWindows, transform_above],
|
||||
[entry.imeWindows, transform_ime],
|
||||
[entry.stacks, transform_stack],
|
||||
[entry.tasks, transform_task],
|
||||
[entry.belowAppWindows, transform_below],
|
||||
[children, transform_window_container_child],
|
||||
],
|
||||
bounds,
|
||||
});
|
||||
}
|
||||
|
||||
function transform_policy(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'policy',
|
||||
name: 'policy',
|
||||
stableId: 'policy',
|
||||
children: [],
|
||||
});
|
||||
}
|
||||
|
||||
function transform_window_service(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'service',
|
||||
name: '',
|
||||
children: [
|
||||
[entry.rootWindowContainer.displays, transform_display_content],
|
||||
[entry.rootWindowContainer.windowContainer.children.reverse(),
|
||||
transform_window_container_child],
|
||||
[[entry.policy], transform_policy],
|
||||
],
|
||||
timestamp: entry.elapsedRealtimeNanos,
|
||||
});
|
||||
}
|
||||
|
||||
function transform_entry(entry) {
|
||||
return transform({
|
||||
obj: entry,
|
||||
kind: 'entry',
|
||||
name: nanos_to_string(entry.elapsedRealtimeNanos),
|
||||
children: [
|
||||
[entry.windowManagerService.rootWindowContainer.displays, transform_display_content],
|
||||
[entry.windowManagerService.rootWindowContainer.windowContainer.children.reverse(),
|
||||
transform_window_container_child],
|
||||
[[entry.windowManagerService.policy], transform_policy],
|
||||
],
|
||||
timestamp: entry.elapsedRealtimeNanos,
|
||||
stableId: 'entry',
|
||||
});
|
||||
}
|
||||
|
||||
function transform_window_trace(entries) {
|
||||
return transform({
|
||||
obj: entries,
|
||||
kind: 'entries',
|
||||
name: 'entries',
|
||||
children: [
|
||||
[entries.entry, transform_entry],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function shortenComponentName(name) {
|
||||
if (!name.includes('/')) {
|
||||
return name
|
||||
}
|
||||
var split = name.split('/');
|
||||
var pkg = split[0];
|
||||
var clazz = split.slice(1).join('/');
|
||||
if (clazz.startsWith(pkg + '.')) {
|
||||
clazz = clazz.slice(pkg.length + 1);
|
||||
return [pkg, clazz].join('/');
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
export { transform_window_service, transform_window_trace };
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020, 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.
|
||||
*/
|
||||
|
||||
const CompatibleFeatures = {
|
||||
DiffVisualization: true,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Should be kept in sync with ENUM is in Google3 under:
|
||||
* google3/wireless/android/tools/android_bug_tool/extension/common/actions
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
/*
|
||||
* Copyright 2020, 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.
|
||||
*/
|
||||
|
||||
// TODO (b/162300507): Get rid of cloning
|
||||
import cloneDeep from 'lodash.clonedeep';
|
||||
|
||||
const DiffType = Object.freeze({
|
||||
export const DiffType = Object.freeze({
|
||||
NONE: 'none',
|
||||
ADDED: 'added',
|
||||
DELETED: 'deleted',
|
||||
@@ -9,7 +26,7 @@ const DiffType = Object.freeze({
|
||||
MODIFIED: 'modified',
|
||||
});
|
||||
|
||||
function defaultModifiedCheck(newNode, oldNode) {
|
||||
export function defaultModifiedCheck(newNode, oldNode) {
|
||||
if (!newNode && !oldNode) {
|
||||
return false;
|
||||
}
|
||||
@@ -23,24 +40,33 @@ function defaultModifiedCheck(newNode, oldNode) {
|
||||
|
||||
function isPrimitive(test) {
|
||||
return test !== Object(test);
|
||||
};
|
||||
}
|
||||
|
||||
class DiffGenerator {
|
||||
export class DiffGenerator {
|
||||
constructor(tree) {
|
||||
if (tree.asRawTreeViewObject) {
|
||||
this.tree = tree.asRawTreeViewObject();
|
||||
} else {
|
||||
this.tree = tree;
|
||||
}
|
||||
}
|
||||
|
||||
compareWith(tree) {
|
||||
if (tree?.asRawTreeViewObject) {
|
||||
this.diffWithTree = tree.asRawTreeViewObject();
|
||||
} else {
|
||||
this.diffWithTree = tree;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
withUniqueNodeId(getNodeId) {
|
||||
this.getNodeId = node => {
|
||||
this.getNodeId = (node) => {
|
||||
const id = getNodeId(node);
|
||||
if (id === null || id === undefined) {
|
||||
console.error("Null node ID for node", node);
|
||||
throw new Error("Node ID can't be null or undefined");
|
||||
console.error('Null node ID for node', node);
|
||||
throw new Error('Node ID can\'t be null or undefined');
|
||||
}
|
||||
return id;
|
||||
};
|
||||
@@ -54,7 +80,8 @@ class DiffGenerator {
|
||||
|
||||
generateDiffTree() {
|
||||
this.newMapping = this._generateIdToNodeMapping(this.tree);
|
||||
this.oldMapping = this.diffWithTree ? this._generateIdToNodeMapping(this.diffWithTree) : {};
|
||||
this.oldMapping = this.diffWithTree ?
|
||||
this._generateIdToNodeMapping(this.diffWithTree) : {};
|
||||
|
||||
const diffTrees =
|
||||
this._generateDiffTree(this.tree, this.diffWithTree, [], []);
|
||||
@@ -62,9 +89,10 @@ class DiffGenerator {
|
||||
let diffTree;
|
||||
if (diffTrees.length > 1) {
|
||||
diffTree = {
|
||||
kind: "",
|
||||
name: "DiffTree",
|
||||
kind: '',
|
||||
name: 'DiffTree',
|
||||
children: diffTrees,
|
||||
stableId: 'DiffTree',
|
||||
};
|
||||
} else {
|
||||
diffTree = diffTrees[0];
|
||||
@@ -177,7 +205,8 @@ class DiffGenerator {
|
||||
|
||||
oldTree = nextOldTree;
|
||||
} else {
|
||||
// TODO: Always have modified check and add modified tags on top of others
|
||||
// TODO: Always have modified check and add modified tags on top of
|
||||
// others
|
||||
// NOTE: Doesn't check for moved and modified at the same time
|
||||
if (this.isModified && this.isModified(newTree, oldTree)) {
|
||||
diffTree.diff = {type: DiffType.MODIFIED};
|
||||
@@ -202,7 +231,7 @@ class DiffGenerator {
|
||||
diffTrees.push(diffTree);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Both newTree and oldTree are undefined...");
|
||||
throw new Error('Both newTree and oldTree are undefined...');
|
||||
}
|
||||
|
||||
return diffTrees;
|
||||
@@ -224,7 +253,7 @@ class DiffGenerator {
|
||||
|
||||
const childDiffTrees = this._generateDiffTree(
|
||||
newChild, oldChild,
|
||||
newTree?.children ?? [], oldTree?.children ?? []
|
||||
newTree?.children ?? [], oldTree?.children ?? [],
|
||||
);
|
||||
diffChildren.push(...childDiffTrees);
|
||||
}
|
||||
@@ -232,5 +261,3 @@ class DiffGenerator {
|
||||
return diffChildren;
|
||||
}
|
||||
}
|
||||
|
||||
export { DiffGenerator, DiffType, defaultModifiedCheck }
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020, 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.
|
||||
*/
|
||||
|
||||
// Returns just the class name and root package information
|
||||
function getComponentClassName(componentFullName) {
|
||||
const classParts = componentFullName.split('.');
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020, 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.
|
||||
*/
|
||||
|
||||
// Find the index of the last element matching the predicate in a sorted array
|
||||
function findLastMatchingSorted(array, predicate) {
|
||||
let a = 0;
|
||||
@@ -30,4 +46,42 @@ const DIRECTION = Object.freeze({
|
||||
FORWARD: 1,
|
||||
});
|
||||
|
||||
export { DIRECTION, findLastMatchingSorted, stableIdCompatibilityFixup }
|
||||
const TimeUnits = Object.freeze({
|
||||
NANO_SECONDS: 'ns',
|
||||
MILLI_SECONDS: 'ms',
|
||||
SECONDS: 's',
|
||||
MINUTES: 'm',
|
||||
HOURS: 'h',
|
||||
DAYS: 'd',
|
||||
});
|
||||
|
||||
function nanosToString(elapsedRealtimeNanos, precision) {
|
||||
const units = [
|
||||
[1000000, TimeUnits.NANO_SECONDS],
|
||||
[1000, TimeUnits.MILLI_SECONDS],
|
||||
[60, TimeUnits.SECONDS],
|
||||
[60, TimeUnits.MINUTES],
|
||||
[24, TimeUnits.HOURS],
|
||||
[Infinity, TimeUnits.DAYS],
|
||||
];
|
||||
|
||||
const parts = [];
|
||||
|
||||
let precisionThresholdReached = false;
|
||||
units.some(([div, timeUnit], i) => {
|
||||
const part = (elapsedRealtimeNanos % div).toFixed()
|
||||
if (timeUnit === precision) {
|
||||
precisionThresholdReached = true;
|
||||
}
|
||||
if (precisionThresholdReached) {
|
||||
parts.push(part + timeUnit);
|
||||
}
|
||||
elapsedRealtimeNanos = Math.floor(elapsedRealtimeNanos / div);
|
||||
|
||||
return elapsedRealtimeNanos == 0;
|
||||
});
|
||||
|
||||
return parts.reverse().join('');
|
||||
}
|
||||
|
||||
export { DIRECTION, findLastMatchingSorted, stableIdCompatibilityFixup, nanosToString, TimeUnits }
|
||||
@@ -44,6 +44,9 @@ const webpackConfig = {
|
||||
polyfill: '@babel/polyfill',
|
||||
main: './src/main.js',
|
||||
},
|
||||
externals: {
|
||||
_: 'lodash',
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js', '.vue'],
|
||||
alias: {
|
||||
|
||||
@@ -995,6 +995,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
|
||||
integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
|
||||
|
||||
"@types/lodash@^4.14.158":
|
||||
version "4.14.158"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.158.tgz#b38ea8b6fe799acd076d7a8d7ab71c26ef77f785"
|
||||
integrity sha512-InCEXJNTv/59yO4VSfuvNrZHt7eeNtWQEgnieIA+mIC+MOWM9arOWG2eQ8Vhk6NbOre6/BidiXhkZYeDY9U35w==
|
||||
|
||||
"@types/long@^4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
|
||||
@@ -2791,6 +2796,15 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.3.0:
|
||||
memory-fs "^0.5.0"
|
||||
tapable "^1.0.0"
|
||||
|
||||
enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.2.0.tgz#5d43bda4a0fd447cb0ebbe71bef8deff8805ad0d"
|
||||
integrity sha512-S7eiFb/erugyd1rLb6mQ3Vuq+EXHv5cpCkNqqIkYkBgN2QdFnyCZzFBleqwGEx4lgNGYij81BWnCrFNK7vxvjQ==
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
memory-fs "^0.5.0"
|
||||
tapable "^1.0.0"
|
||||
|
||||
enquirer@^2.3.5, enquirer@^2.3.6:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
|
||||
@@ -7101,7 +7115,18 @@ ts-loader@^8.0.3:
|
||||
micromatch "^4.0.0"
|
||||
semver "^6.0.0"
|
||||
|
||||
tslib@^1.9.0, tslib@^1.9.3:
|
||||
ts-loader@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.1.tgz#9670dcbce2a8c8506d01a37fee042350d02c8c21"
|
||||
integrity sha512-I9Nmly0ufJoZRMuAT9d5ijsC2B7oSPvUnOJt/GhgoATlPGYfa17VicDKPcqwUCrHpOkCxr/ybLYwbnS4cOxmvQ==
|
||||
dependencies:
|
||||
chalk "^2.3.0"
|
||||
enhanced-resolve "^4.0.0"
|
||||
loader-utils "^1.0.2"
|
||||
micromatch "^4.0.0"
|
||||
semver "^6.0.0"
|
||||
|
||||
tslib@^1.10.0, tslib@^1.9.0, tslib@^1.9.3:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
||||
|
||||
Reference in New Issue
Block a user