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/preset-env": "^7.10.4",
|
||||||
"@babel/register": "^7.10.5",
|
"@babel/register": "^7.10.5",
|
||||||
"@jetbrains/kotlin-webpack-plugin": "^3.0.2",
|
"@jetbrains/kotlin-webpack-plugin": "^3.0.2",
|
||||||
|
"@types/lodash": "^4.14.158",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"compression-webpack-plugin": "^4.0.0",
|
"compression-webpack-plugin": "^4.0.0",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
@@ -47,6 +48,8 @@
|
|||||||
"protobufjs": "^6.10.0",
|
"protobufjs": "^6.10.0",
|
||||||
"source-map-loader": "^1.0.1",
|
"source-map-loader": "^1.0.1",
|
||||||
"style-loader": "^1.2.1",
|
"style-loader": "^1.2.1",
|
||||||
|
"ts-loader": "^8.0.1",
|
||||||
|
"typescript": "^3.9.7",
|
||||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||||
"vue-loader": "^15.9.3",
|
"vue-loader": "^15.9.3",
|
||||||
"vue-style-loader": "^4.1.2",
|
"vue-style-loader": "^4.1.2",
|
||||||
|
|||||||
@@ -35,6 +35,13 @@
|
|||||||
:title="c.long"
|
:title="c.long"
|
||||||
:class="chipClassForChip(c)"
|
:class="chipClassForChip(c)"
|
||||||
>{{c.short}} <!-- No line break on purpose -->
|
>{{c.short}} <!-- No line break on purpose -->
|
||||||
|
<md-tooltip
|
||||||
|
md-delay="300"
|
||||||
|
md-direction="top"
|
||||||
|
style="margin-bottom: -10px"
|
||||||
|
>
|
||||||
|
{{c.long}}
|
||||||
|
</md-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bounds" :style="boundsStyle">
|
<div class="bounds" :style="boundsStyle">
|
||||||
<div
|
<div
|
||||||
class="rect" v-for="r in rects"
|
class="rect" v-for="r in filteredRects"
|
||||||
:style="rectToStyle(r)"
|
:style="rectToStyle(r)"
|
||||||
@click="onClick(r)"
|
@click="onClick(r)"
|
||||||
v-bind:key="`${r.left}-${r.right}-${r.top}-${r.bottom}-${r.ref.name}`"
|
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,
|
return this.rectToStyle({top: 0, left: 0, right: this.boundsC.width,
|
||||||
bottom: this.boundsC.height});
|
bottom: this.boundsC.height});
|
||||||
},
|
},
|
||||||
|
filteredRects() {
|
||||||
|
return this.rects.filter((rect) => rect.ref.visible);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
s(sourceCoordinate) { // translate source into target coordinates
|
s(sourceCoordinate) { // translate source into target coordinates
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ export default {
|
|||||||
itemSelected(item) {
|
itemSelected(item) {
|
||||||
this.hierarchySelected = item;
|
this.hierarchySelected = item;
|
||||||
this.selectedTree = this.getTransformedProperties(item);
|
this.selectedTree = this.getTransformedProperties(item);
|
||||||
this.highlight = item.highlight;
|
this.highlight = item.rect;
|
||||||
this.lastSelectedStableId = item.stableId;
|
this.lastSelectedStableId = item.stableId;
|
||||||
this.$emit('focus');
|
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 jsonProtoDefsLauncher from 'packages/apps/Launcher3/protos/launcher_trace_file.proto';
|
||||||
import protobuf from 'protobufjs';
|
import protobuf from 'protobufjs';
|
||||||
import {transformLayers, transformLayersTrace} from './transform_sf.js';
|
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_transaction_trace} from './transform_transaction.js';
|
||||||
import {transform_wl_outputstate, transform_wayland_trace} from './transform_wl.js';
|
import {transform_wl_outputstate, transform_wayland_trace} from './transform_wl.js';
|
||||||
import {transformProtolog} from './transform_protolog.js';
|
import {transformProtolog} from './transform_protolog.js';
|
||||||
@@ -211,7 +210,7 @@ const FILE_DECODERS = {
|
|||||||
decoderParams: {
|
decoderParams: {
|
||||||
type: FILE_TYPES.WINDOW_MANAGER_TRACE,
|
type: FILE_TYPES.WINDOW_MANAGER_TRACE,
|
||||||
protoType: WmTraceMessage,
|
protoType: WmTraceMessage,
|
||||||
transform: transform_window_trace,
|
transform: WindowManagerTrace.fromProto,
|
||||||
timeline: true,
|
timeline: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -255,7 +254,7 @@ const FILE_DECODERS = {
|
|||||||
type: FILE_TYPES.WINDOW_MANAGER_DUMP,
|
type: FILE_TYPES.WINDOW_MANAGER_DUMP,
|
||||||
mime: 'application/octet-stream',
|
mime: 'application/octet-stream',
|
||||||
protoType: WmDumpMessage,
|
protoType: WmDumpMessage,
|
||||||
transform: transform_window_service,
|
transform: WindowManagerDump.fromProto,
|
||||||
timeline: false,
|
timeline: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -380,7 +379,7 @@ function protoDecoder(buffer, params, fileName, store) {
|
|||||||
const transformed = decodeAndTransformProto(buffer, params, store.displayDefaults);
|
const transformed = decodeAndTransformProto(buffer, params, store.displayDefaults);
|
||||||
let data;
|
let data;
|
||||||
if (params.timeline) {
|
if (params.timeline) {
|
||||||
data = transformed.children;
|
data = transformed.entries ?? transformed.children;
|
||||||
} else {
|
} else {
|
||||||
data = [transformed];
|
data = [transformed];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
import { FILE_TYPES, DUMP_TYPES } from "@/decode.js";
|
import { FILE_TYPES, DUMP_TYPES } from "@/decode.js";
|
||||||
import DumpBase from "./DumpBase";
|
import DumpBase from "./DumpBase";
|
||||||
|
|
||||||
|
import { WindowManagerTraceEntry } from '@/flickerlib';
|
||||||
|
|
||||||
export default class WindowManager extends DumpBase {
|
export default class WindowManager extends DumpBase {
|
||||||
wmDumpFile: any;
|
wmDumpFile: any;
|
||||||
|
|
||||||
@@ -29,4 +31,8 @@ export default class WindowManager extends DumpBase {
|
|||||||
get type() {
|
get type() {
|
||||||
return DUMP_TYPES.WINDOW_MANAGER;
|
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 { FILE_TYPES, TRACE_TYPES } from '@/decode.js';
|
||||||
import TraceBase from './TraceBase';
|
import TraceBase from './TraceBase';
|
||||||
|
|
||||||
|
import { WindowManagerTrace } from '@/flickerlib';
|
||||||
|
|
||||||
export default class WindowManager extends TraceBase {
|
export default class WindowManager extends TraceBase {
|
||||||
wmTraceFile: Object;
|
wmTraceFile: Object;
|
||||||
|
|
||||||
@@ -30,4 +32,8 @@ export default class WindowManager extends TraceBase {
|
|||||||
get type() {
|
get type() {
|
||||||
return TRACE_TYPES.WINDOW_MANAGER;
|
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 = {
|
const CompatibleFeatures = {
|
||||||
DiffVisualization: true,
|
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:
|
* Should be kept in sync with ENUM is in Google3 under:
|
||||||
* google3/wireless/android/tools/android_bug_tool/extension/common/actions
|
* 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';
|
import cloneDeep from 'lodash.clonedeep';
|
||||||
|
|
||||||
const DiffType = Object.freeze({
|
export const DiffType = Object.freeze({
|
||||||
NONE: 'none',
|
NONE: 'none',
|
||||||
ADDED: 'added',
|
ADDED: 'added',
|
||||||
DELETED: 'deleted',
|
DELETED: 'deleted',
|
||||||
@@ -9,7 +26,7 @@ const DiffType = Object.freeze({
|
|||||||
MODIFIED: 'modified',
|
MODIFIED: 'modified',
|
||||||
});
|
});
|
||||||
|
|
||||||
function defaultModifiedCheck(newNode, oldNode) {
|
export function defaultModifiedCheck(newNode, oldNode) {
|
||||||
if (!newNode && !oldNode) {
|
if (!newNode && !oldNode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -23,24 +40,33 @@ function defaultModifiedCheck(newNode, oldNode) {
|
|||||||
|
|
||||||
function isPrimitive(test) {
|
function isPrimitive(test) {
|
||||||
return test !== Object(test);
|
return test !== Object(test);
|
||||||
};
|
}
|
||||||
|
|
||||||
class DiffGenerator {
|
export class DiffGenerator {
|
||||||
constructor(tree) {
|
constructor(tree) {
|
||||||
|
if (tree.asRawTreeViewObject) {
|
||||||
|
this.tree = tree.asRawTreeViewObject();
|
||||||
|
} else {
|
||||||
this.tree = tree;
|
this.tree = tree;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
compareWith(tree) {
|
compareWith(tree) {
|
||||||
|
if (tree?.asRawTreeViewObject) {
|
||||||
|
this.diffWithTree = tree.asRawTreeViewObject();
|
||||||
|
} else {
|
||||||
this.diffWithTree = tree;
|
this.diffWithTree = tree;
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
withUniqueNodeId(getNodeId) {
|
withUniqueNodeId(getNodeId) {
|
||||||
this.getNodeId = node => {
|
this.getNodeId = (node) => {
|
||||||
const id = getNodeId(node);
|
const id = getNodeId(node);
|
||||||
if (id === null || id === undefined) {
|
if (id === null || id === undefined) {
|
||||||
console.error("Null node ID for node", node);
|
console.error('Null node ID for node', node);
|
||||||
throw new Error("Node ID can't be null or undefined");
|
throw new Error('Node ID can\'t be null or undefined');
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
};
|
};
|
||||||
@@ -54,7 +80,8 @@ class DiffGenerator {
|
|||||||
|
|
||||||
generateDiffTree() {
|
generateDiffTree() {
|
||||||
this.newMapping = this._generateIdToNodeMapping(this.tree);
|
this.newMapping = this._generateIdToNodeMapping(this.tree);
|
||||||
this.oldMapping = this.diffWithTree ? this._generateIdToNodeMapping(this.diffWithTree) : {};
|
this.oldMapping = this.diffWithTree ?
|
||||||
|
this._generateIdToNodeMapping(this.diffWithTree) : {};
|
||||||
|
|
||||||
const diffTrees =
|
const diffTrees =
|
||||||
this._generateDiffTree(this.tree, this.diffWithTree, [], []);
|
this._generateDiffTree(this.tree, this.diffWithTree, [], []);
|
||||||
@@ -62,9 +89,10 @@ class DiffGenerator {
|
|||||||
let diffTree;
|
let diffTree;
|
||||||
if (diffTrees.length > 1) {
|
if (diffTrees.length > 1) {
|
||||||
diffTree = {
|
diffTree = {
|
||||||
kind: "",
|
kind: '',
|
||||||
name: "DiffTree",
|
name: 'DiffTree',
|
||||||
children: diffTrees,
|
children: diffTrees,
|
||||||
|
stableId: 'DiffTree',
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
diffTree = diffTrees[0];
|
diffTree = diffTrees[0];
|
||||||
@@ -127,7 +155,7 @@ class DiffGenerator {
|
|||||||
const diffTree = this._cloneNodeWithoutChildren(newTree);
|
const diffTree = this._cloneNodeWithoutChildren(newTree);
|
||||||
|
|
||||||
// Default to no changes
|
// Default to no changes
|
||||||
diffTree.diff = { type: DiffType.NONE };
|
diffTree.diff = {type: DiffType.NONE};
|
||||||
|
|
||||||
if (newId !== oldId) {
|
if (newId !== oldId) {
|
||||||
// A move, addition, or deletion has occurred
|
// A move, addition, or deletion has occurred
|
||||||
@@ -139,14 +167,14 @@ class DiffGenerator {
|
|||||||
// Objected existed in old tree, the counter party
|
// Objected existed in old tree, the counter party
|
||||||
// DELETED_MOVE will be/has been flagged and added to the
|
// DELETED_MOVE will be/has been flagged and added to the
|
||||||
// diffTree when visiting it in the oldTree.
|
// diffTree when visiting it in the oldTree.
|
||||||
diffTree.diff = { type: DiffType.ADDED_MOVE };
|
diffTree.diff = {type: DiffType.ADDED_MOVE};
|
||||||
|
|
||||||
// TODO: Figure out if oldTree is ever visited now...
|
// TODO: Figure out if oldTree is ever visited now...
|
||||||
|
|
||||||
// Switch out oldTree for new one to compare against
|
// Switch out oldTree for new one to compare against
|
||||||
nextOldTree = this.oldMapping[newId];
|
nextOldTree = this.oldMapping[newId];
|
||||||
} else {
|
} else {
|
||||||
diffTree.diff = { type: DiffType.ADDED };
|
diffTree.diff = {type: DiffType.ADDED};
|
||||||
|
|
||||||
// TODO: Figure out if oldTree is ever visited now...
|
// TODO: Figure out if oldTree is ever visited now...
|
||||||
|
|
||||||
@@ -160,13 +188,13 @@ class DiffGenerator {
|
|||||||
const deletedTreeDiff = this._cloneNodeWithoutChildren(oldTree);
|
const deletedTreeDiff = this._cloneNodeWithoutChildren(oldTree);
|
||||||
|
|
||||||
if (this.newMapping[oldId]) {
|
if (this.newMapping[oldId]) {
|
||||||
deletedTreeDiff.diff = { type: DiffType.DELETED_MOVE };
|
deletedTreeDiff.diff = {type: DiffType.DELETED_MOVE};
|
||||||
|
|
||||||
// Stop comparing against oldTree, will be/has been
|
// Stop comparing against oldTree, will be/has been
|
||||||
// visited when object is seen in newTree
|
// visited when object is seen in newTree
|
||||||
nextOldTree = null;
|
nextOldTree = null;
|
||||||
} else {
|
} else {
|
||||||
deletedTreeDiff.diff = { type: DiffType.DELETED };
|
deletedTreeDiff.diff = {type: DiffType.DELETED};
|
||||||
|
|
||||||
// Visit all children to check if they have been deleted or moved
|
// Visit all children to check if they have been deleted or moved
|
||||||
deletedTreeDiff.children = this._visitChildren(null, oldTree);
|
deletedTreeDiff.children = this._visitChildren(null, oldTree);
|
||||||
@@ -177,10 +205,11 @@ class DiffGenerator {
|
|||||||
|
|
||||||
oldTree = nextOldTree;
|
oldTree = nextOldTree;
|
||||||
} else {
|
} 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
|
// NOTE: Doesn't check for moved and modified at the same time
|
||||||
if (this.isModified && this.isModified(newTree, oldTree)) {
|
if (this.isModified && this.isModified(newTree, oldTree)) {
|
||||||
diffTree.diff = { type: DiffType.MODIFIED };
|
diffTree.diff = {type: DiffType.MODIFIED};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,16 +222,16 @@ class DiffGenerator {
|
|||||||
|
|
||||||
// newTree doesn't exists, oldTree has either been moved or deleted.
|
// newTree doesn't exists, oldTree has either been moved or deleted.
|
||||||
if (this.newMapping[oldId]) {
|
if (this.newMapping[oldId]) {
|
||||||
diffTree.diff = { type: DiffType.DELETED_MOVE };
|
diffTree.diff = {type: DiffType.DELETED_MOVE};
|
||||||
} else {
|
} else {
|
||||||
diffTree.diff = { type: DiffType.DELETED };
|
diffTree.diff = {type: DiffType.DELETED};
|
||||||
}
|
}
|
||||||
|
|
||||||
diffTree.children = this._visitChildren(null, oldTree);
|
diffTree.children = this._visitChildren(null, oldTree);
|
||||||
diffTrees.push(diffTree);
|
diffTrees.push(diffTree);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Both newTree and oldTree are undefined...");
|
throw new Error('Both newTree and oldTree are undefined...');
|
||||||
}
|
}
|
||||||
|
|
||||||
return diffTrees;
|
return diffTrees;
|
||||||
@@ -224,7 +253,7 @@ class DiffGenerator {
|
|||||||
|
|
||||||
const childDiffTrees = this._generateDiffTree(
|
const childDiffTrees = this._generateDiffTree(
|
||||||
newChild, oldChild,
|
newChild, oldChild,
|
||||||
newTree?.children ?? [], oldTree?.children ?? []
|
newTree?.children ?? [], oldTree?.children ?? [],
|
||||||
);
|
);
|
||||||
diffChildren.push(...childDiffTrees);
|
diffChildren.push(...childDiffTrees);
|
||||||
}
|
}
|
||||||
@@ -232,5 +261,3 @@ class DiffGenerator {
|
|||||||
return diffChildren;
|
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
|
// Returns just the class name and root package information
|
||||||
function getComponentClassName(componentFullName) {
|
function getComponentClassName(componentFullName) {
|
||||||
const classParts = componentFullName.split('.');
|
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
|
// Find the index of the last element matching the predicate in a sorted array
|
||||||
function findLastMatchingSorted(array, predicate) {
|
function findLastMatchingSorted(array, predicate) {
|
||||||
let a = 0;
|
let a = 0;
|
||||||
@@ -30,4 +46,42 @@ const DIRECTION = Object.freeze({
|
|||||||
FORWARD: 1,
|
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',
|
polyfill: '@babel/polyfill',
|
||||||
main: './src/main.js',
|
main: './src/main.js',
|
||||||
},
|
},
|
||||||
|
externals: {
|
||||||
|
_: 'lodash',
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.tsx', '.ts', '.js', '.vue'],
|
extensions: ['.tsx', '.ts', '.js', '.vue'],
|
||||||
alias: {
|
alias: {
|
||||||
|
|||||||
@@ -995,6 +995,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
|
||||||
integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
|
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":
|
"@types/long@^4.0.1":
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
|
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"
|
memory-fs "^0.5.0"
|
||||||
tapable "^1.0.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:
|
enquirer@^2.3.5, enquirer@^2.3.6:
|
||||||
version "2.3.6"
|
version "2.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
|
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"
|
micromatch "^4.0.0"
|
||||||
semver "^6.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"
|
version "1.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
||||||
|
|||||||
Reference in New Issue
Block a user