[DO NOT MERGE] Full - Compatibilize winscope with master
Bug: 194813677 Test: none Change-Id: Ie55429dcb746f597f80dfdaa68cbef19f5820005
This commit is contained in:
@@ -115,6 +115,11 @@ TRACE_TARGETS = {
|
|||||||
'su root cmd window tracing start\necho "WM trace started."',
|
'su root cmd window tracing start\necho "WM trace started."',
|
||||||
'su root cmd window tracing stop >/dev/null 2>&1'
|
'su root cmd window tracing stop >/dev/null 2>&1'
|
||||||
),
|
),
|
||||||
|
"accessibility_trace": TraceTarget(
|
||||||
|
File("/data/misc/a11ytrace/a11y_trace.pb", "accessibility_trace"),
|
||||||
|
'su root cmd accessibility start-trace\necho "Accessibility trace started."',
|
||||||
|
'su root cmd accessibility stop-trace >/dev/null 2>&1'
|
||||||
|
),
|
||||||
"layers_trace": TraceTarget(
|
"layers_trace": TraceTarget(
|
||||||
File("/data/misc/wmtrace/layers_trace.pb", "layers_trace"),
|
File("/data/misc/wmtrace/layers_trace.pb", "layers_trace"),
|
||||||
'su root service call SurfaceFlinger 1025 i32 1\necho "SF trace started."',
|
'su root service call SurfaceFlinger 1025 i32 1\necho "SF trace started."',
|
||||||
|
|||||||
@@ -5,60 +5,60 @@
|
|||||||
"author": "Adrian Roos <roosa@google.com>",
|
"author": "Adrian Roos <roosa@google.com>",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
|
"dev": "cross-env NODE_ENV=development webpack serve --open --hot",
|
||||||
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules",
|
"build": "cross-env NODE_ENV=production webpack --progress",
|
||||||
"test": "webpack --config webpack.spec.config.js && jasmine dist/bundleSpec.js"
|
"test": "webpack --config webpack.spec.config.js && jasmine dist/bundleSpec.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.3",
|
||||||
"jszip": "^3.5.0",
|
"jszip": "^3.6.0",
|
||||||
"kotlin": "^1.3.72",
|
"kotlin": "^1.5.21",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"ts-loader": "^8.0.3",
|
"ts-loader": "^8.3.0",
|
||||||
"typescript": "^4.0.2",
|
"typescript": "^4.3.5",
|
||||||
"vue": "^2.3.3",
|
"vue": "^2.6.14",
|
||||||
"vue-context": "^5.2.0",
|
"vue-context": "^6.0.0",
|
||||||
"vue-material": "^1.0.0-beta-11",
|
"vue-material": "^1.0.0-beta-15",
|
||||||
"vuex": "^3.4.0"
|
"vuex": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.10.5",
|
"@babel/core": "^7.14.6",
|
||||||
"@babel/polyfill": "^7.10.4",
|
"@babel/polyfill": "^7.12.1",
|
||||||
"@babel/preset-env": "^7.10.4",
|
"@babel/preset-env": "^7.14.7",
|
||||||
"@babel/register": "^7.10.5",
|
"@babel/register": "^7.14.5",
|
||||||
"@jetbrains/kotlin-webpack-plugin": "^3.0.2",
|
"@jetbrains/kotlin-webpack-plugin": "^3.0.2",
|
||||||
"@testing-library/vue": "^5.1.0",
|
"@testing-library/vue": "^5.8.1",
|
||||||
"@types/lodash": "^4.14.158",
|
"@types/lodash": "^4.14.171",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.2.2",
|
||||||
"compression-webpack-plugin": "^4.0.0",
|
"compression-webpack-plugin": "^6.1.1",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.3",
|
||||||
"css-loader": "^3.6.0",
|
"css-loader": "^5.2.7",
|
||||||
"eslint": "^7.1.0",
|
"eslint": "^7.30.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-vue": "^6.2.2",
|
"eslint-plugin-vue": "^7.13.0",
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.2.0",
|
||||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||||
"html-webpack-inline-source-plugin": "^0.0.10",
|
"html-webpack-inline-source-plugin": "^1.0.0-beta.2",
|
||||||
"html-webpack-plugin": "3.2.0",
|
"html-webpack-plugin": "4.5.2",
|
||||||
"husky": "^4.2.5",
|
"husky": "^7.0.0",
|
||||||
"jasmine": "^3.5.0",
|
"jasmine": "^3.8.0",
|
||||||
"lint-staged": ">=10",
|
"lint-staged": "^11.0.1",
|
||||||
"loader-utils": "^2.0.0",
|
"loader-utils": "^2.0.0",
|
||||||
"mini-css-extract-plugin": "^0.9.0",
|
"mini-css-extract-plugin": "^1.6.2",
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||||
"protobufjs": "^6.10.0",
|
"protobufjs": "^6.11.2",
|
||||||
"source-map-loader": "^1.0.1",
|
"source-map-loader": "^1.1.3",
|
||||||
"style-loader": "^1.2.1",
|
"style-loader": "^2.0.0",
|
||||||
"ts-loader": "^8.0.1",
|
"ts-loader": "^8.3.0",
|
||||||
"typescript": "^3.9.7",
|
"typescript": "^4.3.5",
|
||||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||||
"vue-loader": "^15.9.3",
|
"vue-loader": "^15.9.2",
|
||||||
"vue-style-loader": "^4.1.2",
|
"vue-style-loader": "^4.1.3",
|
||||||
"vue-template-compiler": "^2.6.11",
|
"vue-template-compiler": "^2.6.14",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.46.0",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^4.7.2",
|
||||||
"webpack-dev-server": "^3.11.0",
|
"webpack-dev-server": "^3.11.2",
|
||||||
"webpack-merge": "^5.0.9"
|
"webpack-merge": "^5.8.0"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
|
|||||||
35
tools/winscope/src/AccessibilityTraceView.vue
Normal file
35
tools/winscope/src/AccessibilityTraceView.vue
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!-- Copyright (C) 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<TraceView :store="store" :file="file" :summarizer="summarizer" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import TraceView from "@/TraceView.vue"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "AccessibilityTraceView",
|
||||||
|
props: ["store", "file"],
|
||||||
|
components: {
|
||||||
|
TraceView
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
summarizer(item) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
<dataadb class="adbinput" ref="adb" :store="store"
|
<dataadb class="adbinput" ref="adb" :store="store"
|
||||||
@dataReady="onDataReady" @statusChange="setStatus" />
|
@dataReady="onDataReady" @statusChange="setStatus" />
|
||||||
</div>
|
</div>
|
||||||
<div class="input">
|
<div class="input" @dragover.prevent @drop.prevent>
|
||||||
<datainput class="fileinput" ref="input" :store="store"
|
<datainput class="fileinput" ref="input" :store="store"
|
||||||
@dataReady="onDataReady" @statusChange="setStatus" />
|
@dataReady="onDataReady" @statusChange="setStatus" />
|
||||||
</div>
|
</div>
|
||||||
@@ -279,4 +279,18 @@ a {
|
|||||||
.data-view-container {
|
.data-view-container {
|
||||||
padding: 25px 20px 0 20px;
|
padding: 25px 20px 0 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.snackbar-break-words {
|
||||||
|
/* These are technically the same, but use both */
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word;
|
||||||
|
-ms-word-break: break-all;
|
||||||
|
word-break: break-word;
|
||||||
|
/* Adds a hyphen where the word breaks, if supported (No Blink) */
|
||||||
|
-ms-hyphens: auto;
|
||||||
|
-moz-hyphens: auto;
|
||||||
|
-webkit-hyphens: auto;
|
||||||
|
hyphens: auto;
|
||||||
|
padding: 10px 10px 10px 10px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ const DUMPS = {
|
|||||||
|
|
||||||
const proxyFileTypeAdapter = {
|
const proxyFileTypeAdapter = {
|
||||||
'window_trace': FILE_TYPES.WINDOW_MANAGER_TRACE,
|
'window_trace': FILE_TYPES.WINDOW_MANAGER_TRACE,
|
||||||
|
'accessibility_trace': FILE_TYPES.ACCESSIBILITY_TRACE,
|
||||||
'layers_trace': FILE_TYPES.SURFACE_FLINGER_TRACE,
|
'layers_trace': FILE_TYPES.SURFACE_FLINGER_TRACE,
|
||||||
'wl_trace': FILE_TYPES.WAYLAND_TRACE,
|
'wl_trace': FILE_TYPES.WAYLAND_TRACE,
|
||||||
'layers_dump': FILE_TYPES.SURFACE_FLINGER_DUMP,
|
'layers_dump': FILE_TYPES.SURFACE_FLINGER_DUMP,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
|
<div @dragleave="fileDragOut" @dragover="fileDragIn" @drop="handleFileDrop">
|
||||||
<flat-card style="min-width: 50em">
|
<flat-card style="min-width: 50em">
|
||||||
<md-card-header>
|
<md-card-header>
|
||||||
<div class="md-title">Open files</div>
|
<div class="md-title">Open files</div>
|
||||||
@@ -37,16 +38,6 @@
|
|||||||
md-mode="indeterminate"
|
md-mode="indeterminate"
|
||||||
v-show="loadingFiles"
|
v-show="loadingFiles"
|
||||||
/>
|
/>
|
||||||
<div>
|
|
||||||
<md-checkbox v-model="store.displayDefaults" class="md-primary">
|
|
||||||
Show default properties
|
|
||||||
<md-tooltip md-direction="bottom">
|
|
||||||
If checked, shows the value of all properties.
|
|
||||||
Otherwise, hides all properties whose value is the default for its
|
|
||||||
data type.
|
|
||||||
</md-tooltip>
|
|
||||||
</md-checkbox>
|
|
||||||
</div>
|
|
||||||
<div class="md-layout">
|
<div class="md-layout">
|
||||||
<div class="md-layout-item md-small-size-100">
|
<div class="md-layout-item md-small-size-100">
|
||||||
<md-field>
|
<md-field>
|
||||||
@@ -100,7 +91,7 @@
|
|||||||
:md-active.sync="showSnackbar"
|
:md-active.sync="showSnackbar"
|
||||||
md-persistent
|
md-persistent
|
||||||
>
|
>
|
||||||
<span style="white-space: pre-line;">{{ snackbarText }}</span>
|
<p class="snackbar-break-words">{{ snackbarText }}</p>
|
||||||
<div @click="hideSnackbarMessage()">
|
<div @click="hideSnackbarMessage()">
|
||||||
<md-button class="md-icon-button">
|
<md-button class="md-icon-button">
|
||||||
<md-icon style="color: white">close</md-icon>
|
<md-icon style="color: white">close</md-icon>
|
||||||
@@ -108,6 +99,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</md-snackbar>
|
</md-snackbar>
|
||||||
</flat-card>
|
</flat-card>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import FlatCard from './components/FlatCard.vue';
|
import FlatCard from './components/FlatCard.vue';
|
||||||
@@ -145,7 +137,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showSnackbarMessage(message, duration) {
|
showSnackbarMessage(message, duration) {
|
||||||
this.snackbarText = message;
|
this.snackbarText = '\n' + message + '\n';
|
||||||
this.snackbarDuration = duration;
|
this.snackbarDuration = duration;
|
||||||
this.showSnackbar = true;
|
this.showSnackbar = true;
|
||||||
},
|
},
|
||||||
@@ -234,6 +226,18 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
fileDragIn(e){
|
||||||
|
e.preventDefault();
|
||||||
|
},
|
||||||
|
fileDragOut(e){
|
||||||
|
e.preventDefault();
|
||||||
|
},
|
||||||
|
handleFileDrop(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
let droppedFiles = e.dataTransfer.files;
|
||||||
|
if(!droppedFiles) return;
|
||||||
|
this.processFiles(droppedFiles);
|
||||||
|
},
|
||||||
onLoadFile(e) {
|
onLoadFile(e) {
|
||||||
const files = event.target.files || event.dataTransfer.files;
|
const files = event.target.files || event.dataTransfer.files;
|
||||||
this.processFiles(files);
|
this.processFiles(files);
|
||||||
|
|||||||
@@ -30,7 +30,12 @@
|
|||||||
<md-icon>save_alt</md-icon>
|
<md-icon>save_alt</md-icon>
|
||||||
</md-button>
|
</md-button>
|
||||||
</md-card-header>
|
</md-card-header>
|
||||||
|
<AccessibilityTraceView
|
||||||
|
v-if="showInAccessibilityTraceView(file)"
|
||||||
|
:store="store"
|
||||||
|
:file="file"
|
||||||
|
ref="view"
|
||||||
|
/>
|
||||||
<WindowManagerTraceView
|
<WindowManagerTraceView
|
||||||
v-if="showInWindowManagerTraceView(file)"
|
v-if="showInWindowManagerTraceView(file)"
|
||||||
:store="store"
|
:store="store"
|
||||||
@@ -68,6 +73,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import TraceView from '@/TraceView.vue';
|
import TraceView from '@/TraceView.vue';
|
||||||
|
import AccessibilityTraceView from '@/AccessibilityTraceView.vue';
|
||||||
import WindowManagerTraceView from '@/WindowManagerTraceView.vue';
|
import WindowManagerTraceView from '@/WindowManagerTraceView.vue';
|
||||||
import SurfaceFlingerTraceView from '@/SurfaceFlingerTraceView.vue';
|
import SurfaceFlingerTraceView from '@/SurfaceFlingerTraceView.vue';
|
||||||
import TransactionsView from '@/TransactionsView.vue';
|
import TransactionsView from '@/TransactionsView.vue';
|
||||||
@@ -152,6 +158,7 @@ export default {
|
|||||||
'transactionsview': TransactionsView,
|
'transactionsview': TransactionsView,
|
||||||
'logview': LogView,
|
'logview': LogView,
|
||||||
'flat-card': FlatCard,
|
'flat-card': FlatCard,
|
||||||
|
AccessibilityTraceView,
|
||||||
WindowManagerTraceView,
|
WindowManagerTraceView,
|
||||||
SurfaceFlingerTraceView,
|
SurfaceFlingerTraceView,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<md-card-content class="container">
|
<md-card-content class="container">
|
||||||
<div class="navigation">
|
<div class="navigation">
|
||||||
|
<md-content
|
||||||
|
md-tag="md-toolbar"
|
||||||
|
md-elevation="0"
|
||||||
|
class="card-toolbar md-transparent md-dense"
|
||||||
|
>
|
||||||
|
<h2 class="md-title" style="flex: 1">Log View</h2>
|
||||||
<md-button
|
<md-button
|
||||||
class="md-dense md-primary"
|
class="md-dense md-primary"
|
||||||
@click.native="scrollToRow(lastOccuredVisibleIndex)"
|
@click.native="scrollToRow(lastOccuredVisibleIndex)"
|
||||||
@@ -33,6 +39,7 @@
|
|||||||
Pin to latest message
|
Pin to latest message
|
||||||
</md-tooltip>
|
</md-tooltip>
|
||||||
</md-button>
|
</md-button>
|
||||||
|
</md-content>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<vue-context ref="menu">
|
<vue-context ref="menu">
|
||||||
<li>
|
|
||||||
<a href="#" @click.prevent="$emit('collapseAllOtherNodes')">
|
|
||||||
Collapse all other nodes
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</vue-context>
|
</vue-context>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="active-timeline" v-show="minimized">
|
<div class="active-timeline" v-show="minimized">
|
||||||
|
<md-field class="seek-timestamp-field">
|
||||||
|
<label>Search for timestamp</label>
|
||||||
|
<md-input v-model="searchTimestamp"></md-input>
|
||||||
|
</md-field>
|
||||||
|
|
||||||
|
<md-button
|
||||||
|
@click="updateSearchForTimestamp"
|
||||||
|
>Search</md-button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="active-timeline-icon"
|
class="active-timeline-icon"
|
||||||
@click="$refs.navigationTypeSelection.$el
|
@click="$refs.navigationTypeSelection.$el
|
||||||
@@ -81,8 +90,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<md-field
|
<md-field
|
||||||
|
v-if="multipleTraces"
|
||||||
ref="navigationTypeSelection"
|
ref="navigationTypeSelection"
|
||||||
class="nagivation-style-selection-field"
|
class="navigation-style-selection-field"
|
||||||
>
|
>
|
||||||
|
|
||||||
<label>Navigation</label>
|
<label>Navigation</label>
|
||||||
@@ -91,7 +101,8 @@
|
|||||||
name="navigationStyle"
|
name="navigationStyle"
|
||||||
md-dense
|
md-dense
|
||||||
>
|
>
|
||||||
<md-icon-option :value="NAVIGATION_STYLE.GLOBAL"
|
<md-icon-option
|
||||||
|
:value="NAVIGATION_STYLE.GLOBAL"
|
||||||
icon="public"
|
icon="public"
|
||||||
desc="Consider all timelines for navigation"
|
desc="Consider all timelines for navigation"
|
||||||
/>
|
/>
|
||||||
@@ -265,7 +276,7 @@ import {NAVIGATION_STYLE} from './utils/consts';
|
|||||||
import {TRACE_ICONS} from '@/decode.js';
|
import {TRACE_ICONS} from '@/decode.js';
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
import {nanos_to_string} from './transform.js';
|
import {nanos_to_string, string_to_nanos} from './transform.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'overlay',
|
name: 'overlay',
|
||||||
@@ -290,6 +301,7 @@ export default {
|
|||||||
crop: null,
|
crop: null,
|
||||||
cropIntent: null,
|
cropIntent: null,
|
||||||
TRACE_ICONS,
|
TRACE_ICONS,
|
||||||
|
searchTimestamp: '',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@@ -376,7 +388,7 @@ export default {
|
|||||||
default:
|
default:
|
||||||
const split = this.navigationStyle.split('-');
|
const split = this.navigationStyle.split('-');
|
||||||
if (split[0] !== NAVIGATION_STYLE.TARGETED) {
|
if (split[0] !== NAVIGATION_STYLE.TARGETED) {
|
||||||
throw new Error('Unexpected nagivation type');
|
throw new Error('Unexpected navigation type');
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileType = split[1];
|
const fileType = split[1];
|
||||||
@@ -398,7 +410,7 @@ export default {
|
|||||||
default:
|
default:
|
||||||
const split = this.navigationStyle.split('-');
|
const split = this.navigationStyle.split('-');
|
||||||
if (split[0] !== NAVIGATION_STYLE.TARGETED) {
|
if (split[0] !== NAVIGATION_STYLE.TARGETED) {
|
||||||
throw new Error('Unexpected nagivation type');
|
throw new Error('Unexpected navigation type');
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileType = split[1];
|
const fileType = split[1];
|
||||||
@@ -412,8 +424,12 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.navigationStyle === NAVIGATION_STYLE.FOCUSED) {
|
if (this.navigationStyle === NAVIGATION_STYLE.FOCUSED) {
|
||||||
|
//dumps do not have a timeline, so if scrolling over a dump, show merged timeline
|
||||||
|
if (this.focusedFile.timeline) {
|
||||||
return this.focusedFile;
|
return this.focusedFile;
|
||||||
}
|
}
|
||||||
|
return this.mergedTimeline;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.navigationStyle === NAVIGATION_STYLE.CUSTOM) {
|
if (this.navigationStyle === NAVIGATION_STYLE.CUSTOM) {
|
||||||
// TODO: Return custom timeline
|
// TODO: Return custom timeline
|
||||||
@@ -425,12 +441,15 @@ export default {
|
|||||||
.traces[this.navigationStyle.split('-')[1]];
|
.traces[this.navigationStyle.split('-')[1]];
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Unexpected Nagivation Style');
|
throw new Error('Unexpected Navigation Style');
|
||||||
},
|
},
|
||||||
isCropped() {
|
isCropped() {
|
||||||
return this.crop != null &&
|
return this.crop != null &&
|
||||||
(this.crop.left !== 0 || this.crop.right !== 1);
|
(this.crop.left !== 0 || this.crop.right !== 1);
|
||||||
},
|
},
|
||||||
|
multipleTraces() {
|
||||||
|
return this.timelineFiles.length > 1;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
@@ -589,7 +608,7 @@ export default {
|
|||||||
default:
|
default:
|
||||||
const split = this.navigationStyle.split('-');
|
const split = this.navigationStyle.split('-');
|
||||||
if (split[0] !== NAVIGATION_STYLE.TARGETED) {
|
if (split[0] !== NAVIGATION_STYLE.TARGETED) {
|
||||||
throw new Error('Unexpected nagivation type');
|
throw new Error('Unexpected navigation type');
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileType = split[1];
|
const fileType = split[1];
|
||||||
@@ -623,6 +642,17 @@ export default {
|
|||||||
clearSelection() {
|
clearSelection() {
|
||||||
this.crop = null;
|
this.crop = null;
|
||||||
},
|
},
|
||||||
|
updateSearchForTimestamp() {
|
||||||
|
if (/^\d+$/.test(this.searchTimestamp)) {
|
||||||
|
var roundedTimestamp = parseInt(this.searchTimestamp);
|
||||||
|
} else {
|
||||||
|
var roundedTimestamp = string_to_nanos(this.searchTimestamp);
|
||||||
|
}
|
||||||
|
var closestTimestamp = this.mergedTimeline.timeline.reduce(function(prev, curr) {
|
||||||
|
return (Math.abs(curr-roundedTimestamp) < Math.abs(prev-roundedTimestamp) ? curr : prev);
|
||||||
|
});
|
||||||
|
this.$store.dispatch('updateTimelineTime', parseInt(closestTimestamp));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
'timeline': Timeline,
|
'timeline': Timeline,
|
||||||
@@ -816,7 +846,7 @@ export default {
|
|||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nagivation-style-selection-field {
|
.navigation-style-selection-field {
|
||||||
width: 90px;
|
width: 90px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
import {multiply_rect} from './matrix_utils.js';
|
import {multiplyRect} from './matrix_utils.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'rects',
|
name: 'rects',
|
||||||
@@ -46,9 +46,9 @@ export default {
|
|||||||
return this.bounds;
|
return this.bounds;
|
||||||
}
|
}
|
||||||
const width = Math.max(
|
const width = Math.max(
|
||||||
...this.rects.map((r) => multiply_rect(r.transform, r).right));
|
...this.rects.map((r) => multiplyRect(r.transform, r).right));
|
||||||
const height = Math.max(
|
const height = Math.max(
|
||||||
...this.rects.map((r) => multiply_rect(r.transform, r).bottom));
|
...this.rects.map((r) => multiplyRect(r.transform, r).bottom));
|
||||||
return {width, height};
|
return {width, height};
|
||||||
},
|
},
|
||||||
boundsStyle() {
|
boundsStyle() {
|
||||||
@@ -57,8 +57,9 @@ export default {
|
|||||||
},
|
},
|
||||||
filteredRects() {
|
filteredRects() {
|
||||||
return this.rects.filter((rect) => {
|
return this.rects.filter((rect) => {
|
||||||
const isVisible = rect.ref.visible ?? rect.ref.isVisible;
|
const isVisible = rect.ref.isVisible;
|
||||||
console.warn(`Name: ${rect.ref.name} Kind: ${rect.ref.kind} isVisible=${isVisible}`);
|
console.warn(`Name: ${rect.ref.name}`, `Kind: ${rect.ref.kind}`,
|
||||||
|
`isVisible=${isVisible}`);
|
||||||
return isVisible;
|
return isVisible;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -78,11 +79,23 @@ export default {
|
|||||||
const y = this.s(r.top);
|
const y = this.s(r.top);
|
||||||
const w = this.s(r.right) - this.s(r.left);
|
const w = this.s(r.right) - this.s(r.left);
|
||||||
const h = this.s(r.bottom) - this.s(r.top);
|
const h = this.s(r.bottom) - this.s(r.top);
|
||||||
const t = r.transform;
|
|
||||||
|
let t;
|
||||||
|
if (r.transform && r.transform.matrix) {
|
||||||
|
t = r.transform.matrix;
|
||||||
|
} else {
|
||||||
|
t = r.transform;
|
||||||
|
}
|
||||||
|
|
||||||
const tr = t ? `matrix(${t.dsdx}, ${t.dtdx}, ${t.dsdy}, ${t.dtdy}, ` +
|
const tr = t ? `matrix(${t.dsdx}, ${t.dtdx}, ${t.dsdy}, ${t.dtdy}, ` +
|
||||||
`${this.s(t.tx)}, ${this.s(t.ty)})` : '';
|
`${this.s(t.tx)}, ${this.s(t.ty)})` : '';
|
||||||
return `top: ${y}px; left: ${x}px; height: ${h}px; width: ${w}px;` +
|
const rectStyle = `top: ${y}px; left: ` +
|
||||||
|
`${x}px; height: ${h}px; width: ${w}px; ` +
|
||||||
`transform: ${tr}; transform-origin: 0 0;`;
|
`transform: ${tr}; transform-origin: 0 0;`;
|
||||||
|
if (r && r.ref) {
|
||||||
|
console.log(`${r.ref.name} - ${rectStyle}`);
|
||||||
|
}
|
||||||
|
return rectStyle;
|
||||||
},
|
},
|
||||||
onClick(r) {
|
onClick(r) {
|
||||||
this.$emit('rect-click', r.ref);
|
this.$emit('rect-click', r.ref);
|
||||||
|
|||||||
@@ -30,23 +30,23 @@ export default {
|
|||||||
summarizer(layer) {
|
summarizer(layer) {
|
||||||
const summary = [];
|
const summary = [];
|
||||||
|
|
||||||
if (layer.invisibleDueTo) {
|
if (layer?.visibilityReason) {
|
||||||
summary.push({key: 'Invisible due to', value: layer.invisibleDueTo});
|
summary.push({key: 'Invisible due to', value: layer.visibilityReason});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layer.occludedBy?.length > 0) {
|
if (layer?.occludedBy?.length > 0) {
|
||||||
summary.push({key: 'Occluded by', value: layer.occludedBy.join(', ')});
|
summary.push({key: 'Occluded by', value: layer.occludedBy.map(it => it.id).join(', ')});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layer.partiallyOccludedBy?.length > 0) {
|
if (layer?.partiallyOccludedBy?.length > 0) {
|
||||||
summary.push({
|
summary.push({
|
||||||
key: 'Partially occluded by',
|
key: 'Partially occluded by',
|
||||||
value: layer.partiallyOccludedBy.join(', '),
|
value: layer.partiallyOccludedBy.map(it => it.id).join(', '),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layer.coveredBy?.length > 0) {
|
if (layer?.coveredBy?.length > 0) {
|
||||||
summary.push({key: 'Covered by', value: layer.coveredBy.join(', ')});
|
summary.push({key: 'Covered by', value: layer.coveredBy.map(it => it.id).join(', ')});
|
||||||
}
|
}
|
||||||
|
|
||||||
return summary;
|
return summary;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
>
|
>
|
||||||
<h2 class="md-title" style="flex: 1;">Hierarchy</h2>
|
<h2 class="md-title" style="flex: 1;">Hierarchy</h2>
|
||||||
<md-checkbox
|
<md-checkbox
|
||||||
v-model="showHierachyDiff"
|
v-model="showHierarchyDiff"
|
||||||
v-if="diffVisualizationAvailable"
|
v-if="diffVisualizationAvailable"
|
||||||
>
|
>
|
||||||
Show Diff
|
Show Diff
|
||||||
@@ -72,6 +72,19 @@
|
|||||||
class="card-toolbar md-transparent md-dense"
|
class="card-toolbar md-transparent md-dense"
|
||||||
>
|
>
|
||||||
<h2 class="md-title" style="flex: 1">Properties</h2>
|
<h2 class="md-title" style="flex: 1">Properties</h2>
|
||||||
|
<div>
|
||||||
|
<md-checkbox
|
||||||
|
v-model="displayDefaults"
|
||||||
|
@change="checkboxChange"
|
||||||
|
>
|
||||||
|
Show Defaults
|
||||||
|
</md-checkbox>
|
||||||
|
<md-tooltip md-direction="bottom">
|
||||||
|
If checked, shows the value of all properties.
|
||||||
|
Otherwise, hides all properties whose value is
|
||||||
|
the default for its data type.
|
||||||
|
</md-tooltip>
|
||||||
|
</div>
|
||||||
<md-checkbox
|
<md-checkbox
|
||||||
v-model="showPropertiesDiff"
|
v-model="showPropertiesDiff"
|
||||||
v-if="diffVisualizationAvailable"
|
v-if="diffVisualizationAvailable"
|
||||||
@@ -96,7 +109,6 @@
|
|||||||
:item="selectedTree"
|
:item="selectedTree"
|
||||||
:filter="propertyFilter"
|
:filter="propertyFilter"
|
||||||
:collapseChildren="true"
|
:collapseChildren="true"
|
||||||
:useGlobalCollapsedState="true"
|
|
||||||
:elementView="PropertiesTreeElement"
|
:elementView="PropertiesTreeElement"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -104,7 +116,7 @@
|
|||||||
<i class="material-icons none-icon">
|
<i class="material-icons none-icon">
|
||||||
filter_none
|
filter_none
|
||||||
</i>
|
</i>
|
||||||
<span>No element selected in the hierachy.</span>
|
<span>No element selected in the hierarchy.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</flat-card>
|
</flat-card>
|
||||||
@@ -123,6 +135,8 @@ import {DiffGenerator, defaultModifiedCheck} from './utils/diff.js';
|
|||||||
import {TRACE_TYPES, DUMP_TYPES} from './decode.js';
|
import {TRACE_TYPES, DUMP_TYPES} from './decode.js';
|
||||||
import {stableIdCompatibilityFixup} from './utils/utils.js';
|
import {stableIdCompatibilityFixup} from './utils/utils.js';
|
||||||
import {CompatibleFeatures} from './utils/compatibility.js';
|
import {CompatibleFeatures} from './utils/compatibility.js';
|
||||||
|
import {getPropertiesForDisplay} from './flickerlib/mixin';
|
||||||
|
import ObjectFormatter from './flickerlib/ObjectFormatter';
|
||||||
|
|
||||||
function formatProto(obj) {
|
function formatProto(obj) {
|
||||||
if (obj?.prettyPrint) {
|
if (obj?.prettyPrint) {
|
||||||
@@ -164,12 +178,16 @@ export default {
|
|||||||
item: null,
|
item: null,
|
||||||
tree: null,
|
tree: null,
|
||||||
highlight: null,
|
highlight: null,
|
||||||
showHierachyDiff: false,
|
showHierarchyDiff: false,
|
||||||
|
displayDefaults: false,
|
||||||
showPropertiesDiff: false,
|
showPropertiesDiff: false,
|
||||||
PropertiesTreeElement,
|
PropertiesTreeElement,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
checkboxChange(checked) {
|
||||||
|
this.itemSelected(this.item);
|
||||||
|
},
|
||||||
itemSelected(item) {
|
itemSelected(item) {
|
||||||
this.hierarchySelected = item;
|
this.hierarchySelected = item;
|
||||||
this.selectedTree = this.getTransformedProperties(item);
|
this.selectedTree = this.getTransformedProperties(item);
|
||||||
@@ -178,8 +196,9 @@ export default {
|
|||||||
this.$emit('focus');
|
this.$emit('focus');
|
||||||
},
|
},
|
||||||
getTransformedProperties(item) {
|
getTransformedProperties(item) {
|
||||||
|
ObjectFormatter.displayDefaults = this.displayDefaults;
|
||||||
const transformer = new ObjectTransformer(
|
const transformer = new ObjectTransformer(
|
||||||
item.obj,
|
getPropertiesForDisplay(item),
|
||||||
item.name,
|
item.name,
|
||||||
stableIdCompatibilityFixup(item),
|
stableIdCompatibilityFixup(item),
|
||||||
).setOptions({
|
).setOptions({
|
||||||
@@ -189,7 +208,7 @@ export default {
|
|||||||
|
|
||||||
if (this.showPropertiesDiff && this.diffVisualizationAvailable) {
|
if (this.showPropertiesDiff && this.diffVisualizationAvailable) {
|
||||||
const prevItem = this.getItemFromPrevTree(item);
|
const prevItem = this.getItemFromPrevTree(item);
|
||||||
transformer.withDiff(prevItem?.obj);
|
transformer.withDiff(getPropertiesForDisplay(prevItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
return transformer.transform();
|
return transformer.transform();
|
||||||
@@ -200,12 +219,14 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
generateTreeFromItem(item) {
|
generateTreeFromItem(item) {
|
||||||
if (!this.showHierachyDiff || !this.diffVisualizationAvailable) {
|
if (!this.showHierarchyDiff || !this.diffVisualizationAvailable) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DiffGenerator(this.item)
|
const thisItem = this.item;
|
||||||
.compareWith(this.getDataWithOffset(-1))
|
const prevItem = this.getDataWithOffset(-1);
|
||||||
|
return new DiffGenerator(thisItem)
|
||||||
|
.compareWith(prevItem)
|
||||||
.withUniqueNodeId((node) => {
|
.withUniqueNodeId((node) => {
|
||||||
return node.stableId;
|
return node.stableId;
|
||||||
})
|
})
|
||||||
@@ -216,7 +237,7 @@ export default {
|
|||||||
this.item = item;
|
this.item = item;
|
||||||
this.tree = this.generateTreeFromItem(item);
|
this.tree = this.generateTreeFromItem(item);
|
||||||
|
|
||||||
const rects = item.rects //.toArray()
|
const rects = item.rects; // .toArray()
|
||||||
this.rects = [...rects].reverse();
|
this.rects = [...rects].reverse();
|
||||||
this.bounds = item.bounds;
|
this.bounds = item.bounds;
|
||||||
|
|
||||||
@@ -293,7 +314,7 @@ export default {
|
|||||||
selectedIndex() {
|
selectedIndex() {
|
||||||
this.setData(this.file.data[this.file.selectedIndex ?? 0]);
|
this.setData(this.file.data[this.file.selectedIndex ?? 0]);
|
||||||
},
|
},
|
||||||
showHierachyDiff() {
|
showHierarchyDiff() {
|
||||||
this.tree = this.generateTreeFromItem(this.item);
|
this.tree = this.generateTreeFromItem(this.item);
|
||||||
},
|
},
|
||||||
showPropertiesDiff() {
|
showPropertiesDiff() {
|
||||||
@@ -317,7 +338,7 @@ export default {
|
|||||||
const hierarchyPropertyFilter =
|
const hierarchyPropertyFilter =
|
||||||
getFilter(this.hierarchyPropertyFilterString);
|
getFilter(this.hierarchyPropertyFilterString);
|
||||||
return this.store.onlyVisible ? (c) => {
|
return this.store.onlyVisible ? (c) => {
|
||||||
return c.visible && hierarchyPropertyFilter(c);
|
return c.isVisible && hierarchyPropertyFilter(c);
|
||||||
} : hierarchyPropertyFilter;
|
} : hierarchyPropertyFilter;
|
||||||
},
|
},
|
||||||
propertyFilter() {
|
propertyFilter() {
|
||||||
|
|||||||
@@ -33,6 +33,12 @@
|
|||||||
v-for="(surface, index) in sufacesAffectedBy(source)"
|
v-for="(surface, index) in sufacesAffectedBy(source)"
|
||||||
v-bind:key="surface.id"
|
v-bind:key="surface.id"
|
||||||
>
|
>
|
||||||
|
<span
|
||||||
|
v-if="simplifyNames && surface.shortName &&
|
||||||
|
surface.shortName !== surface.name"
|
||||||
|
>{{surface.shortName}}>
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
<!-- eslint-disable-next-line max-len -->
|
<!-- eslint-disable-next-line max-len -->
|
||||||
<span v-if="surface.name" class="surface-name">{{ surface.name }}</span>
|
<span v-if="surface.name" class="surface-name">{{ surface.name }}</span>
|
||||||
<span class="surface-id">
|
<span class="surface-id">
|
||||||
@@ -42,6 +48,7 @@
|
|||||||
<!-- eslint-disable-next-line max-len -->
|
<!-- eslint-disable-next-line max-len -->
|
||||||
<span v-if="index + 1 < sufacesAffectedBy(source).length">, </span>
|
<span v-if="index + 1 < sufacesAffectedBy(source).length">, </span>
|
||||||
</span>
|
</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="extra-info-column">
|
<div class="extra-info-column">
|
||||||
<span v-if="source.identifier">
|
<span v-if="source.identifier">
|
||||||
@@ -59,6 +66,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { shortenName } from './flickerlib/mixin'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'transaction-entry',
|
name: 'transaction-entry',
|
||||||
props: {
|
props: {
|
||||||
@@ -83,6 +92,9 @@ export default {
|
|||||||
prettifyTransactionId: {
|
prettifyTransactionId: {
|
||||||
type: Function,
|
type: Function,
|
||||||
},
|
},
|
||||||
|
simplifyNames: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
currentTimestamp() {
|
currentTimestamp() {
|
||||||
@@ -135,8 +147,12 @@ export default {
|
|||||||
},
|
},
|
||||||
sufacesAffectedBy(transaction) {
|
sufacesAffectedBy(transaction) {
|
||||||
if (transaction.type !== 'transaction') {
|
if (transaction.type !== 'transaction') {
|
||||||
// TODO (b/162402459): Shorten layer name
|
return [
|
||||||
return [{name: transaction.layerName, id: transaction.obj.id}];
|
{
|
||||||
|
name: transaction.layerName,
|
||||||
|
shortName: shortenName(transaction.layerName),
|
||||||
|
id: transaction.obj.id
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
const surfaceIds = new Set();
|
const surfaceIds = new Set();
|
||||||
@@ -145,7 +161,12 @@ export default {
|
|||||||
const id = transaction.obj.id;
|
const id = transaction.obj.id;
|
||||||
if (!surfaceIds.has(id)) {
|
if (!surfaceIds.has(id)) {
|
||||||
surfaceIds.add(id);
|
surfaceIds.add(id);
|
||||||
affectedSurfaces.push({name: transaction.layerName, id});
|
affectedSurfaces.push(
|
||||||
|
{
|
||||||
|
name: transaction.layerName,
|
||||||
|
shortName: shortenName(transaction.layerName),
|
||||||
|
id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
<md-card-content class="container">
|
<md-card-content class="container">
|
||||||
|
|
||||||
<flat-card class="changes card">
|
<flat-card class="changes card">
|
||||||
|
<md-content
|
||||||
|
md-tag="md-toolbar"
|
||||||
|
md-elevation="0"
|
||||||
|
class="card-toolbar md-transparent md-dense"
|
||||||
|
>
|
||||||
|
<h2 class="md-title" style="flex: 1">Transactions</h2>
|
||||||
|
</md-content>
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<md-field>
|
<md-field>
|
||||||
@@ -75,6 +82,11 @@
|
|||||||
<div class="md-helper-text">Press enter to add</div>
|
<div class="md-helper-text">Press enter to add</div>
|
||||||
</md-chips>
|
</md-chips>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<md-checkbox v-model="trace.simplifyNames">
|
||||||
|
Simplify names
|
||||||
|
</md-checkbox>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<virtual-list style="height: 600px; overflow-y: auto;"
|
<virtual-list style="height: 600px; overflow-y: auto;"
|
||||||
@@ -86,6 +98,7 @@
|
|||||||
selectedTransaction,
|
selectedTransaction,
|
||||||
transactionsTrace,
|
transactionsTrace,
|
||||||
prettifyTransactionId,
|
prettifyTransactionId,
|
||||||
|
simplifyNames: trace.simplifyNames,
|
||||||
}"
|
}"
|
||||||
ref="loglist"
|
ref="loglist"
|
||||||
/>
|
/>
|
||||||
@@ -289,7 +302,6 @@ export default {
|
|||||||
const perpareForTreeViewTransform = (change) => {
|
const perpareForTreeViewTransform = (change) => {
|
||||||
this.removeNullFields(change);
|
this.removeNullFields(change);
|
||||||
change[META_DATA_KEY] = {
|
change[META_DATA_KEY] = {
|
||||||
// TODO (b/162402459): Shorten layer name
|
|
||||||
layerName: change.layerName,
|
layerName: change.layerName,
|
||||||
};
|
};
|
||||||
// remove redundant properties
|
// remove redundant properties
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
v-on:selected="immediateChildSelected = true"
|
v-on:selected="immediateChildSelected = true"
|
||||||
v-on:unselected="immediateChildSelected = false"
|
v-on:unselected="immediateChildSelected = false"
|
||||||
:elementView="elementView"
|
:elementView="elementView"
|
||||||
v-on:collapseSibbling="collapseSibbling"
|
v-on:collapseSibling="collapseSibling"
|
||||||
v-on:collapseAllOtherNodes="collapseAllOtherNodes"
|
v-on:collapseAllOtherNodes="collapseAllOtherNodes"
|
||||||
v-on:closeAllContextMenus="closeAllContextMenus"
|
v-on:closeAllContextMenus="closeAllContextMenus"
|
||||||
ref="children"
|
ref="children"
|
||||||
@@ -352,9 +352,9 @@ export default {
|
|||||||
},
|
},
|
||||||
collapseAllOtherNodes() {
|
collapseAllOtherNodes() {
|
||||||
this.$emit('collapseAllOtherNodes');
|
this.$emit('collapseAllOtherNodes');
|
||||||
this.$emit('collapseSibbling', this.item);
|
this.$emit('collapseSibling', this.item);
|
||||||
},
|
},
|
||||||
collapseSibbling(item) {
|
collapseSibling(item) {
|
||||||
if (!this.$refs.children) {
|
if (!this.$refs.children) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ export default {
|
|||||||
summarizer(item) {
|
summarizer(item) {
|
||||||
const summary = [];
|
const summary = [];
|
||||||
|
|
||||||
if (item.obj.isIncompleteReason) {
|
if (item.isIncompleteReason) {
|
||||||
summary.push({key: 'Incomplete state reason', value: item.obj.isIncompleteReason});
|
summary.push({key: 'Incomplete state reason', value: item.isIncompleteReason});
|
||||||
}
|
}
|
||||||
|
|
||||||
return summary;
|
return summary;
|
||||||
|
|||||||
36
tools/winscope/src/config/Configuration.json
Normal file
36
tools/winscope/src/config/Configuration.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"invalidProperties": [
|
||||||
|
"length",
|
||||||
|
"prototype",
|
||||||
|
"ref",
|
||||||
|
"diff",
|
||||||
|
"rects",
|
||||||
|
"chips",
|
||||||
|
"parent",
|
||||||
|
"timestamp",
|
||||||
|
"shortName",
|
||||||
|
"kind",
|
||||||
|
"resolvedChildren",
|
||||||
|
"visibilityReason",
|
||||||
|
"absoluteZ",
|
||||||
|
"name",
|
||||||
|
"children",
|
||||||
|
"stableId"
|
||||||
|
],
|
||||||
|
"intDefColumn": {
|
||||||
|
"WindowLayoutParams.type": "android.view.WindowManager.LayoutParams.WindowType",
|
||||||
|
"WindowLayoutParams.flags": "android.view.WindowManager.LayoutParams.Flags",
|
||||||
|
"WindowLayoutParams.privateFlags": "android.view.WindowManager.LayoutParams.PrivateFlags",
|
||||||
|
"WindowLayoutParams.gravity": "android.view.Gravity.GravityFlags",
|
||||||
|
"WindowLayoutParams.softInputMode": "android.view.WindowManager.LayoutParams.WindowType",
|
||||||
|
"WindowLayoutParams.systemUiVisibilityFlags": "android.view.WindowManager.LayoutParams.SystemUiVisibilityFlags",
|
||||||
|
"WindowLayoutParams.subtreeSystemUiVisibilityFlags": "android.view.WindowManager.LayoutParams.SystemUiVisibilityFlags",
|
||||||
|
"WindowLayoutParams.behavior": "android.view.WindowInsetsController.Behavior",
|
||||||
|
"WindowLayoutParams.fitInsetsSides": "android.view.WindowInsets.Side.InsetsSide",
|
||||||
|
"Configuration.windowingMode": "android.app.WindowConfiguration.WindowingMode",
|
||||||
|
"WindowConfiguration.windowingMode": "android.app.WindowConfiguration.WindowingMode",
|
||||||
|
"Configuration.orientation": "android.content.pm.ActivityInfo.ScreenOrientation",
|
||||||
|
"WindowConfiguration.orientation": "android.content.pm.ActivityInfo.ScreenOrientation",
|
||||||
|
"WindowState.orientation": "android.content.pm.ActivityInfo.ScreenOrientation"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
/* eslint-disable max-len */
|
/* eslint-disable max-len */
|
||||||
|
|
||||||
|
import jsonProtoDefsAccessibility from 'frameworks/base/core/proto/android/server/accessibilitytrace.proto';
|
||||||
import jsonProtoDefsWm from 'frameworks/base/core/proto/android/server/windowmanagertrace.proto';
|
import jsonProtoDefsWm from 'frameworks/base/core/proto/android/server/windowmanagertrace.proto';
|
||||||
import jsonProtoDefsProtoLog from 'frameworks/base/core/proto/android/internal/protolog.proto';
|
import jsonProtoDefsProtoLog from 'frameworks/base/core/proto/android/internal/protolog.proto';
|
||||||
import jsonProtoDefsSf from 'frameworks/native/services/surfaceflinger/layerproto/layerstrace.proto';
|
import jsonProtoDefsSf from 'frameworks/native/services/surfaceflinger/layerproto/layerstrace.proto';
|
||||||
@@ -26,16 +27,16 @@ 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 jsonProtoDefsIme from 'frameworks/base/core/proto/android/view/inputmethod/inputmethodeditortrace.proto';
|
import jsonProtoDefsIme from 'frameworks/base/core/proto/android/view/inputmethod/inputmethodeditortrace.proto';
|
||||||
import protobuf from 'protobufjs';
|
import protobuf from 'protobufjs';
|
||||||
import {transformLayers, transformLayersTrace} from './transform_sf.js';
|
import {transform_accessibility_trace} from './transform_accessibility.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';
|
||||||
import {transform_sysui_trace} from './transform_sys_ui.js';
|
import {transform_sysui_trace} from './transform_sys_ui.js';
|
||||||
import {transform_launcher_trace} from './transform_launcher.js';
|
import {transform_launcher_trace} from './transform_launcher.js';
|
||||||
import {transform_ime_trace_clients, transform_ime_trace_service, transform_ime_trace_managerservice} from './transform_ime.js';
|
import {transform_ime_trace_clients, transform_ime_trace_service, transform_ime_trace_managerservice} from './transform_ime.js';
|
||||||
import {fill_transform_data} from './matrix_utils.js';
|
|
||||||
import {mp4Decoder} from './decodeVideo.js';
|
import {mp4Decoder} from './decodeVideo.js';
|
||||||
|
|
||||||
|
import AccessibilityTrace from '@/traces/Accessibility.ts';
|
||||||
import SurfaceFlingerTrace from '@/traces/SurfaceFlinger.ts';
|
import SurfaceFlingerTrace from '@/traces/SurfaceFlinger.ts';
|
||||||
import WindowManagerTrace from '@/traces/WindowManager.ts';
|
import WindowManagerTrace from '@/traces/WindowManager.ts';
|
||||||
import TransactionsTrace from '@/traces/Transactions.ts';
|
import TransactionsTrace from '@/traces/Transactions.ts';
|
||||||
@@ -52,6 +53,7 @@ import SurfaceFlingerDump from '@/dumps/SurfaceFlinger.ts';
|
|||||||
import WindowManagerDump from '@/dumps/WindowManager.ts';
|
import WindowManagerDump from '@/dumps/WindowManager.ts';
|
||||||
import WaylandDump from '@/dumps/Wayland.ts';
|
import WaylandDump from '@/dumps/Wayland.ts';
|
||||||
|
|
||||||
|
const AccessibilityTraceMessage = lookup_type(jsonProtoDefsAccessibility, 'com.android.server.accessibility.AccessibilityTraceFileProto');
|
||||||
const WmTraceMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerTraceFileProto');
|
const WmTraceMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerTraceFileProto');
|
||||||
const WmDumpMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerServiceDumpProto');
|
const WmDumpMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerServiceDumpProto');
|
||||||
const SfTraceMessage = lookup_type(jsonProtoDefsSf, 'android.surfaceflinger.LayersTraceFileProto');
|
const SfTraceMessage = lookup_type(jsonProtoDefsSf, 'android.surfaceflinger.LayersTraceFileProto');
|
||||||
@@ -62,10 +64,11 @@ const WaylandDumpMessage = lookup_type(jsonProtoDefsWl, 'org.chromium.arc.waylan
|
|||||||
const ProtoLogMessage = lookup_type(jsonProtoDefsProtoLog, 'com.android.internal.protolog.ProtoLogFileProto');
|
const ProtoLogMessage = lookup_type(jsonProtoDefsProtoLog, 'com.android.internal.protolog.ProtoLogFileProto');
|
||||||
const SystemUiTraceMessage = lookup_type(jsonProtoDefsSysUi, 'com.android.systemui.tracing.SystemUiTraceFileProto');
|
const SystemUiTraceMessage = lookup_type(jsonProtoDefsSysUi, 'com.android.systemui.tracing.SystemUiTraceFileProto');
|
||||||
const LauncherTraceMessage = lookup_type(jsonProtoDefsLauncher, 'com.android.launcher3.tracing.LauncherTraceFileProto');
|
const LauncherTraceMessage = lookup_type(jsonProtoDefsLauncher, 'com.android.launcher3.tracing.LauncherTraceFileProto');
|
||||||
const InputMethodClientsTraceMessage = lookup_type(jsonProtoDefsIme, "android.view.inputmethod.InputMethodClientsTraceFileProto");
|
const InputMethodClientsTraceMessage = lookup_type(jsonProtoDefsIme, 'android.view.inputmethod.InputMethodClientsTraceFileProto');
|
||||||
const InputMethodServiceTraceMessage = lookup_type(jsonProtoDefsIme, "android.view.inputmethod.InputMethodServiceTraceFileProto");
|
const InputMethodServiceTraceMessage = lookup_type(jsonProtoDefsIme, 'android.view.inputmethod.InputMethodServiceTraceFileProto');
|
||||||
const InputMethodManagerServiceTraceMessage = lookup_type(jsonProtoDefsIme, "android.view.inputmethod.InputMethodManagerServiceTraceFileProto");
|
const InputMethodManagerServiceTraceMessage = lookup_type(jsonProtoDefsIme, 'android.view.inputmethod.InputMethodManagerServiceTraceFileProto');
|
||||||
|
|
||||||
|
const ACCESSIBILITY_MAGIC_NUMBER = [0x09, 0x41, 0x31, 0x31, 0x59, 0x54, 0x52, 0x41, 0x43]; // .A11YTRAC
|
||||||
const LAYER_TRACE_MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; // .LYRTRACE
|
const LAYER_TRACE_MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; // .LYRTRACE
|
||||||
const WINDOW_TRACE_MAGIC_NUMBER = [0x09, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WINTRACE
|
const WINDOW_TRACE_MAGIC_NUMBER = [0x09, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WINTRACE
|
||||||
const MPEG4_MAGIC_NMBER = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32]; // ....ftypmp42
|
const MPEG4_MAGIC_NMBER = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32]; // ....ftypmp42
|
||||||
@@ -73,11 +76,12 @@ const WAYLAND_TRACE_MAGIC_NUMBER = [0x09, 0x57, 0x59, 0x4c, 0x54, 0x52, 0x41, 0x
|
|||||||
const PROTO_LOG_MAGIC_NUMBER = [0x09, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47]; // .PROTOLOG
|
const PROTO_LOG_MAGIC_NUMBER = [0x09, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47]; // .PROTOLOG
|
||||||
const SYSTEM_UI_MAGIC_NUMBER = [0x09, 0x53, 0x59, 0x53, 0x55, 0x49, 0x54, 0x52, 0x43]; // .SYSUITRC
|
const SYSTEM_UI_MAGIC_NUMBER = [0x09, 0x53, 0x59, 0x53, 0x55, 0x49, 0x54, 0x52, 0x43]; // .SYSUITRC
|
||||||
const LAUNCHER_MAGIC_NUMBER = [0x09, 0x4C, 0x4E, 0x43, 0x48, 0x52, 0x54, 0x52, 0x43]; // .LNCHRTRC
|
const LAUNCHER_MAGIC_NUMBER = [0x09, 0x4C, 0x4E, 0x43, 0x48, 0x52, 0x54, 0x52, 0x43]; // .LNCHRTRC
|
||||||
const IMC_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x43, 0x54, 0x52, 0x41, 0x43, 0x45] //.IMCTRACE
|
const IMC_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x43, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMCTRACE
|
||||||
const IMS_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45] //.IMSTRACE
|
const IMS_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMSTRACE
|
||||||
const IMM_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x4d, 0x54, 0x52, 0x41, 0x43, 0x45] //.IMMTRACE
|
const IMM_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x4d, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMMTRACE
|
||||||
|
|
||||||
const FILE_TYPES = Object.freeze({
|
const FILE_TYPES = Object.freeze({
|
||||||
|
ACCESSIBILITY_TRACE: 'AccessibilityTrace',
|
||||||
WINDOW_MANAGER_TRACE: 'WindowManagerTrace',
|
WINDOW_MANAGER_TRACE: 'WindowManagerTrace',
|
||||||
SURFACE_FLINGER_TRACE: 'SurfaceFlingerTrace',
|
SURFACE_FLINGER_TRACE: 'SurfaceFlingerTrace',
|
||||||
WINDOW_MANAGER_DUMP: 'WindowManagerDump',
|
WINDOW_MANAGER_DUMP: 'WindowManagerDump',
|
||||||
@@ -103,8 +107,10 @@ const PROTO_LOG_ICON = 'notes';
|
|||||||
const SYSTEM_UI_ICON = 'filter_none';
|
const SYSTEM_UI_ICON = 'filter_none';
|
||||||
const LAUNCHER_ICON = 'filter_none';
|
const LAUNCHER_ICON = 'filter_none';
|
||||||
const IME_ICON = 'keyboard';
|
const IME_ICON = 'keyboard';
|
||||||
|
const ACCESSIBILITY_ICON = 'filter_none';
|
||||||
|
|
||||||
const FILE_ICONS = {
|
const FILE_ICONS = {
|
||||||
|
[FILE_TYPES.ACCESSIBILITY_TRACE]: ACCESSIBILITY_ICON,
|
||||||
[FILE_TYPES.WINDOW_MANAGER_TRACE]: WINDOW_MANAGER_ICON,
|
[FILE_TYPES.WINDOW_MANAGER_TRACE]: WINDOW_MANAGER_ICON,
|
||||||
[FILE_TYPES.SURFACE_FLINGER_TRACE]: SURFACE_FLINGER_ICON,
|
[FILE_TYPES.SURFACE_FLINGER_TRACE]: SURFACE_FLINGER_ICON,
|
||||||
[FILE_TYPES.WINDOW_MANAGER_DUMP]: WINDOW_MANAGER_ICON,
|
[FILE_TYPES.WINDOW_MANAGER_DUMP]: WINDOW_MANAGER_ICON,
|
||||||
@@ -125,11 +131,8 @@ function oneOf(dataType) {
|
|||||||
return {oneOf: true, type: dataType};
|
return {oneOf: true, type: dataType};
|
||||||
}
|
}
|
||||||
|
|
||||||
function manyOf(dataType, fold = null) {
|
|
||||||
return {manyOf: true, type: dataType, fold};
|
|
||||||
}
|
|
||||||
|
|
||||||
const TRACE_TYPES = Object.freeze({
|
const TRACE_TYPES = Object.freeze({
|
||||||
|
ACCESSIBILITY: 'AccessibilityTrace',
|
||||||
WINDOW_MANAGER: 'WindowManagerTrace',
|
WINDOW_MANAGER: 'WindowManagerTrace',
|
||||||
SURFACE_FLINGER: 'SurfaceFlingerTrace',
|
SURFACE_FLINGER: 'SurfaceFlingerTrace',
|
||||||
SCREEN_RECORDING: 'ScreenRecording',
|
SCREEN_RECORDING: 'ScreenRecording',
|
||||||
@@ -144,6 +147,12 @@ const TRACE_TYPES = Object.freeze({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const TRACE_INFO = {
|
const TRACE_INFO = {
|
||||||
|
[TRACE_TYPES.ACCESSIBILITY]: {
|
||||||
|
name: 'Accessibility',
|
||||||
|
icon: ACCESSIBILITY_ICON,
|
||||||
|
files: [oneOf(FILE_TYPES.ACCESSIBILITY_TRACE)],
|
||||||
|
constructor: AccessibilityTrace,
|
||||||
|
},
|
||||||
[TRACE_TYPES.WINDOW_MANAGER]: {
|
[TRACE_TYPES.WINDOW_MANAGER]: {
|
||||||
name: 'WindowManager',
|
name: 'WindowManager',
|
||||||
icon: WINDOW_MANAGER_ICON,
|
icon: WINDOW_MANAGER_ICON,
|
||||||
@@ -261,6 +270,16 @@ export const TRACE_ICONS = {
|
|||||||
|
|
||||||
// TODO: Rename name to defaultName
|
// TODO: Rename name to defaultName
|
||||||
const FILE_DECODERS = {
|
const FILE_DECODERS = {
|
||||||
|
[FILE_TYPES.ACCESSIBILITY_TRACE]: {
|
||||||
|
name: 'Accessibility trace',
|
||||||
|
decoder: protoDecoder,
|
||||||
|
decoderParams: {
|
||||||
|
type: FILE_TYPES.ACCESSIBILITY_TRACE,
|
||||||
|
protoType: AccessibilityTraceMessage,
|
||||||
|
transform: transform_accessibility_trace,
|
||||||
|
timeline: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
[FILE_TYPES.WINDOW_MANAGER_TRACE]: {
|
[FILE_TYPES.WINDOW_MANAGER_TRACE]: {
|
||||||
name: 'WindowManager trace',
|
name: 'WindowManager trace',
|
||||||
decoder: protoDecoder,
|
decoder: protoDecoder,
|
||||||
@@ -278,7 +297,7 @@ const FILE_DECODERS = {
|
|||||||
type: FILE_TYPES.SURFACE_FLINGER_TRACE,
|
type: FILE_TYPES.SURFACE_FLINGER_TRACE,
|
||||||
mime: 'application/octet-stream',
|
mime: 'application/octet-stream',
|
||||||
protoType: SfTraceMessage,
|
protoType: SfTraceMessage,
|
||||||
transform: transformLayersTrace,
|
transform: SurfaceFlingerTrace.fromProto,
|
||||||
timeline: true,
|
timeline: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -300,8 +319,8 @@ const FILE_DECODERS = {
|
|||||||
type: FILE_TYPES.SURFACE_FLINGER_DUMP,
|
type: FILE_TYPES.SURFACE_FLINGER_DUMP,
|
||||||
mime: 'application/octet-stream',
|
mime: 'application/octet-stream',
|
||||||
protoType: SfDumpMessage,
|
protoType: SfDumpMessage,
|
||||||
transform: (decoded) => transformLayers(true /* includesCompositionState*/, decoded),
|
transform: SurfaceFlingerDump.fromProto,
|
||||||
timeline: false,
|
timeline: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[FILE_TYPES.WINDOW_MANAGER_DUMP]: {
|
[FILE_TYPES.WINDOW_MANAGER_DUMP]: {
|
||||||
@@ -312,7 +331,7 @@ const FILE_DECODERS = {
|
|||||||
mime: 'application/octet-stream',
|
mime: 'application/octet-stream',
|
||||||
protoType: WmDumpMessage,
|
protoType: WmDumpMessage,
|
||||||
transform: WindowManagerDump.fromProto,
|
transform: WindowManagerDump.fromProto,
|
||||||
timeline: false,
|
timeline: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[FILE_TYPES.WAYLAND_DUMP]: {
|
[FILE_TYPES.WAYLAND_DUMP]: {
|
||||||
@@ -323,7 +342,7 @@ const FILE_DECODERS = {
|
|||||||
mime: 'application/octet-stream',
|
mime: 'application/octet-stream',
|
||||||
protoType: WaylandDumpMessage,
|
protoType: WaylandDumpMessage,
|
||||||
transform: transform_wl_outputstate,
|
transform: transform_wl_outputstate,
|
||||||
timeline: false,
|
timeline: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[FILE_TYPES.SCREEN_RECORDING]: {
|
[FILE_TYPES.SCREEN_RECORDING]: {
|
||||||
@@ -443,11 +462,6 @@ function modifyProtoFields(protoObj, displayDefaults) {
|
|||||||
protoObj[fieldName] = fieldProperties.defaultValue;
|
protoObj[fieldName] = fieldProperties.defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldProperties.type === 'TransformProto') {
|
|
||||||
fill_transform_data(protoObj[fieldName]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldProperties.resolvedType && fieldProperties.resolvedType.valuesById) {
|
if (fieldProperties.resolvedType && fieldProperties.resolvedType.valuesById) {
|
||||||
protoObj[fieldName] = fieldProperties.resolvedType.valuesById[protoObj[fieldProperties.name]];
|
protoObj[fieldName] = fieldProperties.resolvedType.valuesById[protoObj[fieldProperties.name]];
|
||||||
continue;
|
continue;
|
||||||
@@ -524,6 +538,9 @@ function detectAndDecode(buffer, fileName, store) {
|
|||||||
if (arrayStartsWith(buffer, LAYER_TRACE_MAGIC_NUMBER)) {
|
if (arrayStartsWith(buffer, LAYER_TRACE_MAGIC_NUMBER)) {
|
||||||
return decodedFile(FILE_TYPES.SURFACE_FLINGER_TRACE, buffer, fileName, store);
|
return decodedFile(FILE_TYPES.SURFACE_FLINGER_TRACE, buffer, fileName, store);
|
||||||
}
|
}
|
||||||
|
if (arrayStartsWith(buffer, ACCESSIBILITY_MAGIC_NUMBER)) {
|
||||||
|
return decodedFile(FILE_TYPES.ACCESSIBILITY_TRACE, buffer, fileName, store);
|
||||||
|
}
|
||||||
if (arrayStartsWith(buffer, WINDOW_TRACE_MAGIC_NUMBER)) {
|
if (arrayStartsWith(buffer, WINDOW_TRACE_MAGIC_NUMBER)) {
|
||||||
return decodedFile(FILE_TYPES.WINDOW_MANAGER_TRACE, buffer, fileName, store);
|
return decodedFile(FILE_TYPES.WINDOW_MANAGER_TRACE, buffer, fileName, store);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
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 LayersTraceEntry from '../flickerlib/layers/LayerTraceEntry'
|
||||||
|
|
||||||
export default class SurfaceFlinger extends DumpBase {
|
export default class SurfaceFlinger extends DumpBase {
|
||||||
sfDumpFile: any;
|
sfDumpFile: any;
|
||||||
@@ -30,4 +31,12 @@ export default class SurfaceFlinger extends DumpBase {
|
|||||||
get type() {
|
get type() {
|
||||||
return DUMP_TYPES.SURFACE_FLINGER;
|
return DUMP_TYPES.SURFACE_FLINGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static fromProto(proto: any): LayersTraceEntry {
|
||||||
|
return LayersTraceEntry.fromProto(
|
||||||
|
/*protos */ proto.layers,
|
||||||
|
/* timestamp */ 0,
|
||||||
|
/* hwcBlob */ ""
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ export default class WindowManager extends DumpBase {
|
|||||||
return DUMP_TYPES.WINDOW_MANAGER;
|
return DUMP_TYPES.WINDOW_MANAGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromProto(proto): WindowManagerTrace {
|
static fromProto(proto: any): WindowManagerTrace {
|
||||||
return WindowManagerTrace.fromDump(proto);
|
return WindowManagerTrace.fromDump(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
35
tools/winscope/src/flickerlib/LayersTrace.ts
Normal file
35
tools/winscope/src/flickerlib/LayersTrace.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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 { LayersTrace } from "./common"
|
||||||
|
import LayerTraceEntry from './layers/LayerTraceEntry'
|
||||||
|
|
||||||
|
LayersTrace.fromProto = function (proto: any): LayersTrace {
|
||||||
|
const entries = []
|
||||||
|
for (const entryProto of proto.entry) {
|
||||||
|
const transformedEntry = LayerTraceEntry.fromProto(
|
||||||
|
/* protos */ entryProto.layers.layers,
|
||||||
|
/* timestamp */ entryProto.elapsedRealtimeNanos,
|
||||||
|
/* hwcBlob */ entryProto.hwcBlob);
|
||||||
|
|
||||||
|
entries.push(transformedEntry);
|
||||||
|
}
|
||||||
|
const source = null;
|
||||||
|
const trace = new LayersTrace(entries, source);
|
||||||
|
return trace;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LayersTrace;
|
||||||
@@ -14,48 +14,84 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {toBounds, toBuffer, toColor, toPoint, toRect,
|
import {toSize, toBuffer, toColor, toPoint, toRect,
|
||||||
toRectF, toRegion, toTransform} from './common';
|
toRectF, toRegion, toTransform} from './common';
|
||||||
import intDefMapping from
|
import intDefMapping from
|
||||||
'../../../../../prebuilts/misc/common/winscope/intDefMapping.json';
|
'../../../../../prebuilts/misc/common/winscope/intDefMapping.json';
|
||||||
|
import config from '../config/Configuration.json'
|
||||||
|
|
||||||
|
function readIntdefMap(): Map<string, string> {
|
||||||
|
const map = new Map<string, string>();
|
||||||
|
const keys = Object.keys(config.intDefColumn);
|
||||||
|
|
||||||
|
keys.forEach(key => {
|
||||||
|
const value = config.intDefColumn[key];
|
||||||
|
map.set(key, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
export default class ObjectFormatter {
|
export default class ObjectFormatter {
|
||||||
private static INVALID_ELEMENT_PROPERTIES = ['length', 'name', 'prototype', 'children',
|
static displayDefaults: boolean = false
|
||||||
'childrenWindows', 'ref', 'root', 'layers', 'resolvedChildren']
|
private static INVALID_ELEMENT_PROPERTIES = config.invalidProperties;
|
||||||
|
|
||||||
private static FLICKER_INTDEF_MAP = new Map([
|
private static FLICKER_INTDEF_MAP = readIntdefMap();
|
||||||
[`WindowLayoutParams.type`, `android.view.WindowManager.LayoutParams.WindowType`],
|
|
||||||
[`WindowLayoutParams.flags`, `android.view.WindowManager.LayoutParams.Flags`],
|
|
||||||
[`WindowLayoutParams.privateFlags`, `android.view.WindowManager.LayoutParams.PrivateFlags`],
|
|
||||||
[`WindowLayoutParams.gravity`, `android.view.Gravity.GravityFlags`],
|
|
||||||
[`WindowLayoutParams.softInputMode`, `android.view.WindowManager.LayoutParams.WindowType`],
|
|
||||||
[`WindowLayoutParams.systemUiVisibilityFlags`, `android.view.WindowManager.LayoutParams.SystemUiVisibilityFlags`],
|
|
||||||
[`WindowLayoutParams.subtreeSystemUiVisibilityFlags`, `android.view.WindowManager.LayoutParams.SystemUiVisibilityFlags`],
|
|
||||||
[`WindowLayoutParams.behavior`, `android.view.WindowInsetsController.Behavior`],
|
|
||||||
[`WindowLayoutParams.fitInsetsSides`, `android.view.WindowInsets.Side.InsetsSide`],
|
|
||||||
|
|
||||||
[`Configuration.windowingMode`, `android.app.WindowConfiguration.WindowingMode`],
|
static cloneObject(entry: any): any {
|
||||||
[`WindowConfiguration.windowingMode`, `android.app.WindowConfiguration.WindowingMode`],
|
let obj: any = {}
|
||||||
[`Configuration.orientation`, `android.content.pm.ActivityInfo.ScreenOrientation`],
|
const properties = ObjectFormatter.getProperties(entry);
|
||||||
[`WindowConfiguration.orientation`, `android.content.pm.ActivityInfo.ScreenOrientation`],
|
properties.forEach(prop => obj[prop] = entry[prop]);
|
||||||
[`WindowState.orientation`, `android.content.pm.ActivityInfo.ScreenOrientation`],
|
return obj;
|
||||||
])
|
}
|
||||||
|
|
||||||
|
static getProperties(entry: any): string[] {
|
||||||
|
var props = [];
|
||||||
|
let obj = entry;
|
||||||
|
|
||||||
|
do {
|
||||||
|
const properties = Object.getOwnPropertyNames(obj).filter(it => {
|
||||||
|
// filter out functions
|
||||||
|
if (typeof(entry[it]) === 'function') return false;
|
||||||
|
// internal propertires from kotlinJs
|
||||||
|
if (it.includes(`$`)) return false;
|
||||||
|
// private kotlin variables from kotlin
|
||||||
|
if (it.startsWith(`_`)) return false;
|
||||||
|
// some predefined properties used only internally (e.g., children, ref, diff)
|
||||||
|
if (this.INVALID_ELEMENT_PROPERTIES.includes(it)) return false;
|
||||||
|
// Flicker object properties or arrays
|
||||||
|
if (!entry[it]) return false;
|
||||||
|
const value = entry[it]
|
||||||
|
// only non-empty arrays of non-flicker objects (otherwise they are in hierarchy)
|
||||||
|
if (Array.isArray(value) && value.length > 0) return !value[0].stableId
|
||||||
|
// non-flicker object
|
||||||
|
return !value.stableId;
|
||||||
|
});
|
||||||
|
properties.forEach(function (prop) {
|
||||||
|
if (typeof(entry[prop]) !== 'function' && props.indexOf(prop) === -1) {
|
||||||
|
props.push(prop);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} while (obj = Object.getPrototypeOf(obj));
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
static format(obj: any): {} {
|
static format(obj: any): {} {
|
||||||
const entries = Object.entries(obj)
|
const properties = this.getProperties(obj);
|
||||||
.filter(it => !it[0].includes(`$`))
|
const sortedProperties = properties.sort()
|
||||||
.filter(it => !this.INVALID_ELEMENT_PROPERTIES.includes(it[0]))
|
|
||||||
const sortedEntries = entries.sort()
|
|
||||||
|
|
||||||
const result: any = {}
|
const result: any = {}
|
||||||
sortedEntries.forEach(entry => {
|
sortedProperties.forEach(entry => {
|
||||||
const key = entry[0]
|
const key = entry;
|
||||||
const value: any = entry[1]
|
const value: any = obj[key];
|
||||||
|
|
||||||
if (value) {
|
if (value || (this.displayDefaults && value !== undefined && value !== null)) {
|
||||||
// flicker obj
|
// flicker obj
|
||||||
if (value.prettyPrint) {
|
if (value.prettyPrint) {
|
||||||
|
const isEmpty = value.isEmpty === true;
|
||||||
|
if (!isEmpty || this.displayDefaults) {
|
||||||
result[key] = value.prettyPrint()
|
result[key] = value.prettyPrint()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// converted proto to flicker
|
// converted proto to flicker
|
||||||
const translatedObject = this.translateObject(value)
|
const translatedObject = this.translateObject(value)
|
||||||
@@ -63,7 +99,11 @@ export default class ObjectFormatter {
|
|||||||
result[key] = translatedObject.prettyPrint()
|
result[key] = translatedObject.prettyPrint()
|
||||||
// objects - recursive call
|
// objects - recursive call
|
||||||
} else if (value && typeof(value) == `object`) {
|
} else if (value && typeof(value) == `object`) {
|
||||||
result[key] = this.format(value)
|
const childObj = this.format(value) as any
|
||||||
|
const isEmpty = Object.entries(childObj).length == 0 || childObj.isEmpty
|
||||||
|
if (!isEmpty || this.displayDefaults) {
|
||||||
|
result[key] = childObj
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// values
|
// values
|
||||||
result[key] = this.translateIntDef(obj, key, value)
|
result[key] = this.translateIntDef(obj, key, value)
|
||||||
@@ -73,7 +113,8 @@ export default class ObjectFormatter {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return Object.freeze(result)
|
// return Object.freeze(result)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,7 +127,7 @@ export default class ObjectFormatter {
|
|||||||
private static translateObject(obj) {
|
private static translateObject(obj) {
|
||||||
const type = obj?.$type?.name
|
const type = obj?.$type?.name
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case `SizeProto`: return toBounds(obj)
|
case `SizeProto`: return toSize(obj)
|
||||||
case `ActiveBufferProto`: return toBuffer(obj)
|
case `ActiveBufferProto`: return toBuffer(obj)
|
||||||
case `ColorProto`: return toColor(obj)
|
case `ColorProto`: return toColor(obj)
|
||||||
case `PointProto`: return toPoint(obj)
|
case `PointProto`: return toPoint(obj)
|
||||||
|
|||||||
@@ -14,9 +14,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { asRawTreeViewObject } from '../utils/diff.js'
|
|
||||||
import { getPropertiesForDisplay } from './mixin'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
KeyguardControllerState,
|
KeyguardControllerState,
|
||||||
RootWindowContainer,
|
RootWindowContainer,
|
||||||
@@ -26,17 +23,20 @@ import {
|
|||||||
|
|
||||||
import WindowContainer from "./windows/WindowContainer"
|
import WindowContainer from "./windows/WindowContainer"
|
||||||
|
|
||||||
WindowManagerState.fromProto = function ({proto, timestamp = 0, where = ""}): WindowManagerState {
|
WindowManagerState.fromProto = function (proto: any, timestamp: number = 0, where: string = ""): WindowManagerState {
|
||||||
var inputMethodWIndowAppToken = ""
|
var inputMethodWIndowAppToken = "";
|
||||||
if (proto.inputMethodWindow != null) {
|
if (proto.inputMethodWindow != null) {
|
||||||
proto.inputMethodWindow.hashCode.toString(16)
|
proto.inputMethodWindow.hashCode.toString(16)
|
||||||
}
|
};
|
||||||
const rootWindowContainer = newRootWindowContainer(proto.rootWindowContainer)
|
|
||||||
const keyguardControllerState = newKeyguardControllerState(
|
const rootWindowContainer = createRootWindowContainer(proto.rootWindowContainer);
|
||||||
proto.rootWindowContainer.keyguardController)
|
const keyguardControllerState = createKeyguardControllerState(
|
||||||
|
proto.rootWindowContainer.keyguardController);
|
||||||
|
const policy = createWindowManagerPolicy(proto.policy);
|
||||||
|
|
||||||
const entry = new WindowManagerState(
|
const entry = new WindowManagerState(
|
||||||
where,
|
where,
|
||||||
newWindowManagerPolicy(proto.policy),
|
policy,
|
||||||
proto.focusedApp,
|
proto.focusedApp,
|
||||||
proto.focusedDisplayId,
|
proto.focusedDisplayId,
|
||||||
proto.focusedWindow?.title ?? "",
|
proto.focusedWindow?.title ?? "",
|
||||||
@@ -47,26 +47,30 @@ WindowManagerState.fromProto = function ({proto, timestamp = 0, where = ""}): Wi
|
|||||||
rootWindowContainer,
|
rootWindowContainer,
|
||||||
keyguardControllerState,
|
keyguardControllerState,
|
||||||
timestamp = timestamp
|
timestamp = timestamp
|
||||||
)
|
);
|
||||||
|
|
||||||
entry.kind = entry.constructor.name
|
|
||||||
entry.rects = entry.windowStates.reverse().map(it => it.rect)
|
|
||||||
if (!entry.isComplete()) {
|
|
||||||
entry.isIncompleteReason = entry.getIsIncompleteReason()
|
|
||||||
}
|
|
||||||
entry.obj = getPropertiesForDisplay(proto, entry)
|
|
||||||
entry.shortName = entry.name
|
|
||||||
entry.chips = []
|
|
||||||
entry.visible = true
|
|
||||||
entry.rawTreeViewObject = asRawTreeViewObject(entry)
|
|
||||||
|
|
||||||
|
addAttributes(entry, proto);
|
||||||
console.warn("Created ", entry.kind, " stableId=", entry.stableId)
|
console.warn("Created ", entry.kind, " stableId=", entry.stableId)
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
|
|
||||||
function newWindowManagerPolicy(proto): WindowManagerPolicy {
|
function addAttributes(entry: WindowManagerState, proto: any) {
|
||||||
|
entry.kind = entry.constructor.name;
|
||||||
|
// There no JVM/JS translation for Longs yet
|
||||||
|
entry.timestampMs = entry.timestamp.toString();
|
||||||
|
entry.rects = entry.windowStates.reverse().map(it => it.rect);
|
||||||
|
if (!entry.isComplete()) {
|
||||||
|
entry.isIncompleteReason = entry.getIsIncompleteReason();
|
||||||
|
}
|
||||||
|
entry.proto = proto;
|
||||||
|
entry.shortName = entry.name;
|
||||||
|
entry.chips = [];
|
||||||
|
entry.isVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWindowManagerPolicy(proto: any): WindowManagerPolicy {
|
||||||
return new WindowManagerPolicy(
|
return new WindowManagerPolicy(
|
||||||
proto.focusedAppToken || "",
|
proto.focusedAppToken ?? "",
|
||||||
proto.forceStatusBar,
|
proto.forceStatusBar,
|
||||||
proto.forceStatusBarFromKeyguard,
|
proto.forceStatusBarFromKeyguard,
|
||||||
proto.keyguardDrawComplete,
|
proto.keyguardDrawComplete,
|
||||||
@@ -79,36 +83,35 @@ function newWindowManagerPolicy(proto): WindowManagerPolicy {
|
|||||||
proto.rotationMode,
|
proto.rotationMode,
|
||||||
proto.screenOnFully,
|
proto.screenOnFully,
|
||||||
proto.windowManagerDrawComplete
|
proto.windowManagerDrawComplete
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function newRootWindowContainer(proto): RootWindowContainer {
|
function createRootWindowContainer(proto: any): RootWindowContainer {
|
||||||
const children = proto.windowContainer.children.reverse()
|
|
||||||
.filter(it => it != null)
|
|
||||||
.map(it => WindowContainer.childrenFromProto(it, /* isActivityInTree */ false))
|
|
||||||
const windowContainer = WindowContainer.fromProto(
|
const windowContainer = WindowContainer.fromProto(
|
||||||
{proto: proto.windowContainer, children: children})
|
/* proto */ proto.windowContainer,
|
||||||
if (windowContainer == null) {
|
/* childrenProto */ proto.windowContainer.children.reverse()
|
||||||
throw "Window container should not be null: " + JSON.stringify(proto)
|
);
|
||||||
}
|
|
||||||
const entry = new RootWindowContainer(windowContainer)
|
|
||||||
|
|
||||||
return entry
|
if (windowContainer == null) {
|
||||||
|
throw new Error(`Window container should not be null.\n${JSON.stringify(proto)}`);
|
||||||
|
}
|
||||||
|
const entry = new RootWindowContainer(windowContainer);
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
function newKeyguardControllerState(proto): KeyguardControllerState {
|
function createKeyguardControllerState(proto: any): KeyguardControllerState {
|
||||||
const keyguardOccludedStates = {}
|
const keyguardOccludedStates = {};
|
||||||
|
|
||||||
if (proto) {
|
if (proto) {
|
||||||
proto.keyguardOccludedStates.forEach(it =>
|
proto.keyguardOccludedStates.forEach(it =>
|
||||||
keyguardOccludedStates[it.displayId] = it.keyguardOccluded)
|
keyguardOccludedStates[it.displayId] = it.keyguardOccluded);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new KeyguardControllerState(
|
return new KeyguardControllerState(
|
||||||
proto?.isAodShowing ?? false,
|
proto?.isAodShowing ?? false,
|
||||||
proto?.isKeyguardShowing ?? false,
|
proto?.isKeyguardShowing ?? false,
|
||||||
keyguardOccludedStates
|
keyguardOccludedStates
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WindowManagerState;
|
export default WindowManagerState;
|
||||||
@@ -17,23 +17,22 @@
|
|||||||
import { WindowManagerTrace } from "./common"
|
import { WindowManagerTrace } from "./common"
|
||||||
import WindowManagerState from "./WindowManagerState"
|
import WindowManagerState from "./WindowManagerState"
|
||||||
|
|
||||||
WindowManagerTrace.fromProto = function (proto) {
|
WindowManagerTrace.fromProto = function (proto: any) {
|
||||||
const entries = []
|
const entries = [];
|
||||||
for (const entryProto of proto.entry) {
|
for (const entryProto of proto.entry) {
|
||||||
const transformedEntry = WindowManagerState.fromProto({
|
const transformedEntry = WindowManagerState.fromProto(
|
||||||
proto: entryProto.windowManagerService,
|
entryProto.windowManagerService,
|
||||||
timestamp: entryProto.elapsedRealtimeNanos,
|
entryProto.elapsedRealtimeNanos,
|
||||||
where: entryProto.where})
|
entryProto.where);
|
||||||
|
|
||||||
entries.push(transformedEntry)
|
entries.push(transformedEntry);
|
||||||
}
|
}
|
||||||
const source = null
|
const source = null;
|
||||||
const sourceChecksum = null
|
return new WindowManagerTrace(entries, source);
|
||||||
return new WindowManagerTrace(entries, source, sourceChecksum)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowManagerTrace.fromDump = function(proto): WindowManagerTrace {
|
WindowManagerTrace.fromDump = function(proto: any): WindowManagerTrace {
|
||||||
return WindowManagerState.fromProto({proto: proto})
|
return WindowManagerState.fromProto(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WindowManagerTrace;
|
export default WindowManagerTrace;
|
||||||
|
|||||||
@@ -17,46 +17,58 @@
|
|||||||
// Imports all the compiled common Flicker library classes and exports them
|
// Imports all the compiled common Flicker library classes and exports them
|
||||||
// as clean es6 modules rather than having them be commonjs modules
|
// as clean es6 modules rather than having them be commonjs modules
|
||||||
|
|
||||||
const WindowManagerTrace = require('flicker').com.android.server.wm.traces.common.
|
// WM
|
||||||
windowmanager.WindowManagerTrace;
|
const WindowManagerTrace = require('flicker').com.android.server.wm.traces.
|
||||||
const WindowManagerState = require('flicker').com.android.server.wm.traces.common.
|
common.windowmanager.WindowManagerTrace;
|
||||||
windowmanager.WindowManagerState;
|
const WindowManagerState = require('flicker').com.android.server.wm.traces.
|
||||||
|
common.windowmanager.WindowManagerState;
|
||||||
const Activity = require('flicker').com.android.server.wm.traces.common.
|
const Activity = require('flicker').com.android.server.wm.traces.common.
|
||||||
windowmanager.windows.Activity;
|
windowmanager.windows.Activity;
|
||||||
const Configuration = require('flicker').com.android.server.wm.traces.common.
|
const Configuration = require('flicker').com.android.server.wm.traces.common.
|
||||||
windowmanager.windows.Configuration;
|
windowmanager.windows.Configuration;
|
||||||
const ConfigurationContainer = require('flicker').com.android.server.wm.traces.common.
|
const ConfigurationContainer = require('flicker').com.android.server.wm.traces.
|
||||||
windowmanager.windows.ConfigurationContainer;
|
common.windowmanager.windows.ConfigurationContainer;
|
||||||
const DisplayArea = require('flicker').com.android.server.wm.traces.common.
|
const DisplayArea = require('flicker').com.android.server.wm.traces.common.
|
||||||
windowmanager.windows.DisplayArea;
|
windowmanager.windows.DisplayArea;
|
||||||
const DisplayContent = require('flicker').com.android.server.wm.traces.common.
|
const DisplayContent = require('flicker').com.android.server.wm.traces.common.
|
||||||
windowmanager.windows.DisplayContent;
|
windowmanager.windows.DisplayContent;
|
||||||
const KeyguardControllerState = require('flicker').com.android.server.wm.traces.common.
|
const KeyguardControllerState = require('flicker').com.android.server.wm.
|
||||||
windowmanager.windows.KeyguardControllerState;
|
traces.common.windowmanager.windows.KeyguardControllerState;
|
||||||
const RootWindowContainer = require('flicker').com.android.server.wm.traces.common.
|
const RootWindowContainer = require('flicker').com.android.server.wm.traces.
|
||||||
windowmanager.windows.RootWindowContainer;
|
common.windowmanager.windows.RootWindowContainer;
|
||||||
const Task = require('flicker').com.android.server.wm.traces.common.
|
const Task = require('flicker').com.android.server.wm.traces.common.
|
||||||
windowmanager.windows.Task;
|
windowmanager.windows.Task;
|
||||||
const TaskFragment = require('flicker').com.android.server.wm.traces.common.
|
const TaskFragment = require('flicker').com.android.server.wm.traces.common.
|
||||||
windowmanager.windows.TaskFragment;
|
windowmanager.windows.TaskFragment;
|
||||||
const WindowConfiguration = require('flicker').com.android.server.wm.traces.common.
|
const WindowConfiguration = require('flicker').com.android.server.wm.traces.
|
||||||
windowmanager.windows.WindowConfiguration;
|
common.windowmanager.windows.WindowConfiguration;
|
||||||
const WindowContainer = require('flicker').com.android.server.wm.traces.common.
|
const WindowContainer = require('flicker').com.android.server.wm.traces.common.
|
||||||
windowmanager.windows.WindowContainer;
|
windowmanager.windows.WindowContainer;
|
||||||
const WindowLayoutParams= require('flicker').com.android.server.wm.traces.common.
|
const WindowLayoutParams= require('flicker').com.android.server.wm.traces.
|
||||||
windowmanager.windows.WindowLayoutParams;
|
common.windowmanager.windows.WindowLayoutParams;
|
||||||
const WindowManagerPolicy = require('flicker').com.android.server.wm.traces.common.
|
const WindowManagerPolicy = require('flicker').com.android.server.wm.traces.
|
||||||
windowmanager.windows.WindowManagerPolicy;
|
common.windowmanager.windows.WindowManagerPolicy;
|
||||||
const WindowState = require('flicker').com.android.server.wm.traces.common.
|
const WindowState = require('flicker').com.android.server.wm.traces.common.
|
||||||
windowmanager.windows.WindowState;
|
windowmanager.windows.WindowState;
|
||||||
const WindowToken = require('flicker').com.android.server.wm.traces.common.
|
const WindowToken = require('flicker').com.android.server.wm.traces.common.
|
||||||
windowmanager.windows.WindowToken;
|
windowmanager.windows.WindowToken;
|
||||||
|
|
||||||
const Matrix = require('flicker').com.android.server.wm.traces.common.layers.Transform.Matrix;
|
// SF
|
||||||
const Transform = require('flicker').com.android.server.wm.traces.common.layers.Transform;
|
const Layer = require('flicker').com.android.server.wm.traces.common.
|
||||||
|
layers.Layer;
|
||||||
|
const LayerTraceEntry = require('flicker').com.android.server.wm.traces.common.
|
||||||
|
layers.LayerTraceEntry;
|
||||||
|
const LayerTraceEntryBuilder = require('flicker').com.android.server.wm.traces.
|
||||||
|
common.layers.LayerTraceEntryBuilder;
|
||||||
|
const LayersTrace = require('flicker').com.android.server.wm.traces.common.
|
||||||
|
layers.LayersTrace;
|
||||||
|
const Matrix = require('flicker').com.android.server.wm.traces.common.layers.
|
||||||
|
Transform.Matrix;
|
||||||
|
const Transform = require('flicker').com.android.server.wm.traces.common.
|
||||||
|
layers.Transform;
|
||||||
|
|
||||||
const Bounds = require('flicker').com.android.server.wm.traces.common.Bounds;
|
// Common
|
||||||
|
const Size = require('flicker').com.android.server.wm.traces.common.Size;
|
||||||
const Buffer = require('flicker').com.android.server.wm.traces.common.Buffer;
|
const Buffer = require('flicker').com.android.server.wm.traces.common.Buffer;
|
||||||
const Color = require('flicker').com.android.server.wm.traces.common.Color;
|
const Color = require('flicker').com.android.server.wm.traces.common.Color;
|
||||||
const Point = require('flicker').com.android.server.wm.traces.common.Point;
|
const Point = require('flicker').com.android.server.wm.traces.common.Point;
|
||||||
@@ -64,70 +76,129 @@ const Rect = require('flicker').com.android.server.wm.traces.common.Rect;
|
|||||||
const RectF = require('flicker').com.android.server.wm.traces.common.RectF;
|
const RectF = require('flicker').com.android.server.wm.traces.common.RectF;
|
||||||
const Region = require('flicker').com.android.server.wm.traces.common.Region;
|
const Region = require('flicker').com.android.server.wm.traces.common.Region;
|
||||||
|
|
||||||
function toBounds(proto) {
|
const EMPTY_BUFFER = new Buffer(0, 0, 0, 0);
|
||||||
|
const EMPTY_COLOR = new Color(-1, -1, -1, 0);
|
||||||
|
const EMPTY_RECT = new Rect(0, 0, 0, 0);
|
||||||
|
const EMPTY_RECTF = new RectF(0, 0, 0, 0);
|
||||||
|
const EMPTY_POINT = new Point(0, 0);
|
||||||
|
const EMPTY_MATRIX = new Matrix(0, 0, 0, 0, 0, 0);
|
||||||
|
const EMPTY_TRANSFORM = new Transform(0, EMPTY_MATRIX);
|
||||||
|
|
||||||
|
function toSize(proto) {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return EMPTY_BOUNDS;
|
||||||
}
|
}
|
||||||
return new Bounds(proto.width ?? proto.w ?? 0, proto.height ?? proto.h ?? 0)
|
const width = proto.width ?? proto.w ?? 0;
|
||||||
|
const height = proto.height ?? proto.h ?? 0;
|
||||||
|
if (width || height) {
|
||||||
|
return new Size(width, height);
|
||||||
|
}
|
||||||
|
return EMPTY_BOUNDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toBuffer(proto) {
|
function toBuffer(proto) {
|
||||||
if (proto == null) {
|
const width = proto?.width ?? 0;
|
||||||
return null
|
const height = proto?.height ?? 0;
|
||||||
|
const stride = proto?.stride ?? 0;
|
||||||
|
const format = proto?.format ?? 0;
|
||||||
|
|
||||||
|
if (width || height || stride || format) {
|
||||||
|
return new Buffer(width, height, stride, format);
|
||||||
}
|
}
|
||||||
return new Buffer(proto.width ?? 0, proto.height ?? 0, proto.stride ?? 0, proto.format ?? 0)
|
return EMPTY_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toColor(proto) {
|
function toColor(proto) {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return EMPTY_COLOR;
|
||||||
}
|
}
|
||||||
return new Color(proto.r ?? 0, proto.g ?? 0, proto.b ?? 0, proto.a ?? 0)
|
const r = proto.r ?? 0;
|
||||||
|
const g = proto.g ?? 0;
|
||||||
|
const b = proto.b ?? 0;
|
||||||
|
const a = proto.a ?? 0;
|
||||||
|
if (r || g || b || a) {
|
||||||
|
return new Color(r, g, b, a);
|
||||||
|
}
|
||||||
|
return EMPTY_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toPoint(proto) {
|
function toPoint(proto) {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
return new Point(proto.x ?? 0, proto.y ?? 0)
|
const x = proto.x ?? 0;
|
||||||
|
const y = proto.y ?? 0;
|
||||||
|
if (x || y) {
|
||||||
|
return new Point(x, y);
|
||||||
|
}
|
||||||
|
return EMPTY_POINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toRect(proto) {
|
function toRect(proto) {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return EMPTY_RECT;
|
||||||
}
|
}
|
||||||
return new Rect(proto.left ?? 0, proto.top ?? 0, proto.right ?? 0, proto.bottom ?? 0)
|
|
||||||
|
const left = proto?.left ?? 0;
|
||||||
|
const top = proto?.top ?? 0;
|
||||||
|
const right = proto?.right ?? 0;
|
||||||
|
const bottom = proto?.bottom ?? 0;
|
||||||
|
if (left || top || right || bottom) {
|
||||||
|
return new Rect(left, top, right, bottom);
|
||||||
|
}
|
||||||
|
return EMPTY_RECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toRectF(proto) {
|
function toRectF(proto) {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return EMPTY_RECTF;
|
||||||
}
|
}
|
||||||
return new RectF(proto.left ?? 0, proto.top ?? 0, proto.right ?? 0, proto.bottom ?? 0)
|
|
||||||
|
const left = proto?.left ?? 0;
|
||||||
|
const top = proto?.top ?? 0;
|
||||||
|
const right = proto?.right ?? 0;
|
||||||
|
const bottom = proto?.bottom ?? 0;
|
||||||
|
if (left || top || right || bottom) {
|
||||||
|
return new RectF(left, top, right, bottom);
|
||||||
|
}
|
||||||
|
return EMPTY_RECTF;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toRegion(proto) {
|
function toRegion(proto) {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rects = []
|
const rects = [];
|
||||||
for (let rectNr in proto.rect) {
|
for (let x = 0; x < proto.rect.length; x++) {
|
||||||
const rect = proto.rect[rectNr]
|
const rect = proto.rect[x];
|
||||||
const parsedRect = toRect(rect)
|
const parsedRect = toRect(rect);
|
||||||
rects.push(parsedRect)
|
rects.push(parsedRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Region(rects)
|
return new Region(rects);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toTransform(proto) {
|
function toTransform(proto) {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return EMPTY_TRANSFORM;
|
||||||
}
|
}
|
||||||
const matrix = new Matrix(proto.dsdx ?? 0, proto.dtdx ?? 0,
|
const dsdx = proto.dsdx ?? 0;
|
||||||
proto.tx ?? 0, proto.dsdy ?? 0, proto.dtdy ?? 0, proto.ty ?? 0)
|
const dtdx = proto.dtdx ?? 0;
|
||||||
return new Transform(proto.type ?? 0, matrix)
|
const tx = proto.tx ?? 0;
|
||||||
|
const dsdy = proto.dsdy ?? 0;
|
||||||
|
const dtdy = proto.dtdy ?? 0;
|
||||||
|
const ty = proto.ty ?? 0;
|
||||||
|
|
||||||
|
if (dsdx || dtdx || tx || dsdy || dtdy || ty) {
|
||||||
|
const matrix = new Matrix(dsdx, dtdx, tx, dsdy, dtdy, ty);
|
||||||
|
return new Transform(proto.type ?? 0, matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proto.type) {
|
||||||
|
return new Transform(proto.type ?? 0, EMPTY_MATRIX);
|
||||||
|
}
|
||||||
|
return EMPTY_TRANSFORM;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -148,19 +219,27 @@ export {
|
|||||||
WindowManagerPolicy,
|
WindowManagerPolicy,
|
||||||
WindowManagerTrace,
|
WindowManagerTrace,
|
||||||
WindowManagerState,
|
WindowManagerState,
|
||||||
Bounds,
|
// SF
|
||||||
|
Layer,
|
||||||
|
LayerTraceEntry,
|
||||||
|
LayerTraceEntryBuilder,
|
||||||
|
LayersTrace,
|
||||||
|
Transform,
|
||||||
|
Matrix,
|
||||||
|
// Common
|
||||||
|
Size,
|
||||||
Buffer,
|
Buffer,
|
||||||
Color,
|
Color,
|
||||||
Point,
|
Point,
|
||||||
Rect,
|
Rect,
|
||||||
RectF,
|
RectF,
|
||||||
Region,
|
Region,
|
||||||
toBounds,
|
toSize,
|
||||||
toBuffer,
|
toBuffer,
|
||||||
toColor,
|
toColor,
|
||||||
toPoint,
|
toPoint,
|
||||||
toRect,
|
toRect,
|
||||||
toRectF,
|
toRectF,
|
||||||
toRegion,
|
toRegion,
|
||||||
toTransform
|
toTransform,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,12 +14,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import LayersTrace from './LayersTrace';
|
||||||
import WindowManagerState from './WindowManagerState';
|
import WindowManagerState from './WindowManagerState';
|
||||||
import WindowManagerTrace from './WindowManagerTrace';
|
import WindowManagerTrace from './WindowManagerTrace';
|
||||||
|
import ObjectFormatter from './ObjectFormatter';
|
||||||
/**
|
/**
|
||||||
* Entry point into the flickerlib for Winscope.
|
* Entry point into the flickerlib for Winscope.
|
||||||
* Expose everything we want Winscope to have access to here.
|
* Expose everything we want Winscope to have access to here.
|
||||||
*/
|
*/
|
||||||
export {WindowManagerState, WindowManagerTrace};
|
export {ObjectFormatter, LayersTrace, WindowManagerState, WindowManagerTrace};
|
||||||
|
|
||||||
|
|||||||
95
tools/winscope/src/flickerlib/layers/Layer.ts
Normal file
95
tools/winscope/src/flickerlib/layers/Layer.ts
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021, 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 { Layer, Rect, toBuffer, toColor, toRect, toRectF, toRegion } from "../common"
|
||||||
|
import { shortenName } from '../mixin'
|
||||||
|
import { RELATIVE_Z_CHIP, GPU_CHIP, HWC_CHIP } from '../treeview/Chips'
|
||||||
|
import Transform from './Transform'
|
||||||
|
|
||||||
|
Layer.fromProto = function (proto: any): Layer {
|
||||||
|
const visibleRegion = toRegion(proto.visibleRegion)
|
||||||
|
const activeBuffer = toBuffer(proto.activeBuffer)
|
||||||
|
const bounds = toRectF(proto.bounds)
|
||||||
|
const color = toColor(proto.color)
|
||||||
|
const screenBounds = toRectF(proto.screenBounds)
|
||||||
|
const sourceBounds = toRectF(proto.sourceBounds)
|
||||||
|
const transform = Transform.fromProto(proto.transform, proto.position)
|
||||||
|
const bufferTransform = Transform.fromProto(proto.bufferTransform, /* position */ null)
|
||||||
|
const hwcCrop = toRectF(proto.hwcCrop)
|
||||||
|
const hwcFrame = toRect(proto.hwcFrame)
|
||||||
|
let crop: Rect
|
||||||
|
if (proto.crop) {
|
||||||
|
crop = toRect(proto.crop)
|
||||||
|
};
|
||||||
|
|
||||||
|
const entry = new Layer(
|
||||||
|
proto.name ?? ``,
|
||||||
|
proto.id,
|
||||||
|
proto.parent,
|
||||||
|
proto.z,
|
||||||
|
visibleRegion,
|
||||||
|
activeBuffer,
|
||||||
|
proto.flags,
|
||||||
|
bounds,
|
||||||
|
color,
|
||||||
|
proto.isOpaque,
|
||||||
|
proto.shadowRadius,
|
||||||
|
proto.cornerRadius,
|
||||||
|
proto.type ?? ``,
|
||||||
|
screenBounds,
|
||||||
|
transform,
|
||||||
|
sourceBounds,
|
||||||
|
proto.currFrame,
|
||||||
|
proto.effectiveScalingMode,
|
||||||
|
bufferTransform,
|
||||||
|
proto.hwcCompositionType,
|
||||||
|
hwcCrop,
|
||||||
|
hwcFrame,
|
||||||
|
proto.backgroundBlurRadius,
|
||||||
|
crop,
|
||||||
|
proto.isRelativeOf,
|
||||||
|
proto.zOrderRelativeOf
|
||||||
|
);
|
||||||
|
|
||||||
|
addAttributes(entry, proto);
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
|
||||||
|
function addAttributes(entry: Layer, proto: any) {
|
||||||
|
entry.kind = `${entry.id}`;
|
||||||
|
entry.shortName = shortenName(entry.name);
|
||||||
|
entry.proto = proto;
|
||||||
|
entry.rect = entry.bounds;
|
||||||
|
entry.rect.transform = entry.transform;
|
||||||
|
entry.rect.ref = entry;
|
||||||
|
entry.rect.label = entry.name;
|
||||||
|
entry.chips = [];
|
||||||
|
updateChips(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateChips(entry) {
|
||||||
|
if ((entry.zOrderRelativeOf || -1) !== -1) {
|
||||||
|
entry.chips.push(RELATIVE_Z_CHIP);
|
||||||
|
}
|
||||||
|
if (entry.hwcCompositionType === 'CLIENT') {
|
||||||
|
entry.chips.push(GPU_CHIP);
|
||||||
|
} else if (entry.hwcCompositionType === 'DEVICE' || entry.hwcCompositionType === 'SOLID_COLOR') {
|
||||||
|
entry.chips.push(HWC_CHIP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layer;
|
||||||
66
tools/winscope/src/flickerlib/layers/LayerTraceEntry.ts
Normal file
66
tools/winscope/src/flickerlib/layers/LayerTraceEntry.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021, 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 { LayerTraceEntry, LayerTraceEntryBuilder } from "../common"
|
||||||
|
import Layer from './Layer'
|
||||||
|
import { VISIBLE_CHIP, RELATIVE_Z_PARENT_CHIP, MISSING_LAYER } from '../treeview/Chips'
|
||||||
|
|
||||||
|
LayerTraceEntry.fromProto = function (protos: any[], timestamp: number, hwcBlob: string, where: string = ''): LayerTraceEntry {
|
||||||
|
const layers = protos.map(it => Layer.fromProto(it));
|
||||||
|
const builder = new LayerTraceEntryBuilder(timestamp, layers, hwcBlob, where);
|
||||||
|
const entry: LayerTraceEntry = builder.build();
|
||||||
|
|
||||||
|
updateChildren(entry);
|
||||||
|
addAttributes(entry, protos);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addAttributes(entry: LayerTraceEntry, protos: any) {
|
||||||
|
entry.kind = "entry"
|
||||||
|
// There no JVM/JS translation for Longs yet
|
||||||
|
entry.timestampMs = entry.timestamp.toString()
|
||||||
|
entry.rects = entry.visibleLayers
|
||||||
|
.sort((a, b) => (b.absoluteZ > a.absoluteZ) ? 1 : (a.absoluteZ == b.absoluteZ) ? 0 : -1)
|
||||||
|
.map(it => it.rect);
|
||||||
|
|
||||||
|
// Avoid parsing the entry root because it is an array of layers
|
||||||
|
// containing all trace information, this slows down the property tree.
|
||||||
|
// Instead parse only key properties for debugging
|
||||||
|
const entryIds = {}
|
||||||
|
protos.forEach(it =>
|
||||||
|
entryIds[it.id] = `\nparent=${it.parent}\ntype=${it.type}\nname=${it.name}`
|
||||||
|
);
|
||||||
|
entry.proto = entryIds;
|
||||||
|
entry.shortName = entry.name;
|
||||||
|
entry.chips = [];
|
||||||
|
entry.isVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateChildren(entry: LayerTraceEntry) {
|
||||||
|
entry.flattenedLayers.forEach(it => {
|
||||||
|
if (it.isVisible) {
|
||||||
|
it.chips.push(VISIBLE_CHIP);
|
||||||
|
}
|
||||||
|
if (it.zOrderRelativeOf) {
|
||||||
|
it.chips.push(RELATIVE_Z_PARENT_CHIP);
|
||||||
|
}
|
||||||
|
if (it.isMissing) {
|
||||||
|
it.chips.push(MISSING_LAYER);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LayerTraceEntry;
|
||||||
90
tools/winscope/src/flickerlib/layers/Transform.ts
Normal file
90
tools/winscope/src/flickerlib/layers/Transform.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021, 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, Matrix } from "../common"
|
||||||
|
|
||||||
|
Transform.fromProto = function (transformProto, positionProto): Transform {
|
||||||
|
const entry = new Transform(
|
||||||
|
transformProto?.type ?? 0,
|
||||||
|
getMatrix(transformProto, positionProto))
|
||||||
|
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMatrix(transform, position): Matrix {
|
||||||
|
const x = position?.x ?? 0
|
||||||
|
const y = position?.y ?? 0
|
||||||
|
|
||||||
|
if (transform == null || isSimpleTransform(transform.type)) {
|
||||||
|
return getDefaultTransform(transform?.type, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Matrix(transform.dsdx, transform.dtdx, x, transform.dsdy, transform.dtdy, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultTransform(type, x, y): Matrix {
|
||||||
|
// IDENTITY
|
||||||
|
if (!type) {
|
||||||
|
return new Matrix(1, 0, x, 0, 1, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROT_270 = ROT_90|FLIP_H|FLIP_V
|
||||||
|
if (isFlagSet(type, ROT_90_VAL | FLIP_V_VAL | FLIP_H_VAL)) {
|
||||||
|
return new Matrix(0, -1, x, 1, 0, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROT_180 = FLIP_H|FLIP_V
|
||||||
|
if (isFlagSet(type, FLIP_V_VAL | FLIP_H_VAL)) {
|
||||||
|
return new Matrix(-1, 0, x, 0, -1, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROT_90
|
||||||
|
if (isFlagSet(type, ROT_90_VAL)) {
|
||||||
|
return new Matrix(0, 1, x, -1, 0, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDENTITY
|
||||||
|
if (isFlagClear(type, SCALE_VAL | ROTATE_VAL)) {
|
||||||
|
return new Matrix(1, 0, x, 0, 1, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unknown transform type ${type}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFlagSet(type, bits): Boolean {
|
||||||
|
var type = type || 0;
|
||||||
|
return (type & bits) === bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFlagClear(type, bits): Boolean {
|
||||||
|
return (type & bits) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSimpleTransform(type): Boolean {
|
||||||
|
return isFlagClear(type, ROT_INVALID_VAL | SCALE_VAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* transform type flags */
|
||||||
|
const ROTATE_VAL = 0x0002
|
||||||
|
const SCALE_VAL = 0x0004
|
||||||
|
|
||||||
|
/* orientation flags */
|
||||||
|
const FLIP_H_VAL = 0x0100 // (1 << 0 << 8)
|
||||||
|
const FLIP_V_VAL = 0x0200 // (1 << 1 << 8)
|
||||||
|
const ROT_90_VAL = 0x0400 // (1 << 2 << 8)
|
||||||
|
const ROT_INVALID_VAL = 0x8000 // (0x80 << 8)
|
||||||
|
|
||||||
|
export default Transform
|
||||||
@@ -22,12 +22,22 @@ import ObjectFormatter from "./ObjectFormatter"
|
|||||||
* @param entry WM hierarchy element
|
* @param entry WM hierarchy element
|
||||||
* @param proto Associated proto object
|
* @param proto Associated proto object
|
||||||
*/
|
*/
|
||||||
export function getPropertiesForDisplay(proto: any, entry: any): any {
|
export function getPropertiesForDisplay(entry: any): any {
|
||||||
let obj = Object.assign({}, entry)
|
if (!entry) {
|
||||||
if (obj.children) delete obj.children
|
return
|
||||||
// obj = ObjectFormatter.format(obj)
|
}
|
||||||
|
|
||||||
obj.proto = Object.assign({}, proto)
|
let obj: any = {}
|
||||||
|
const properties = ObjectFormatter.getProperties(entry)
|
||||||
|
properties.forEach(prop => obj[prop] = entry[prop]);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
if (obj.children) delete obj.children
|
||||||
|
if (obj.proto) delete obj.proto
|
||||||
|
|
||||||
|
obj.proto = Object.assign({}, entry.proto)
|
||||||
if (obj.proto.children) delete obj.proto.children
|
if (obj.proto.children) delete obj.proto.children
|
||||||
if (obj.proto.childWindows) delete obj.proto.childWindows
|
if (obj.proto.childWindows) delete obj.proto.childWindows
|
||||||
if (obj.proto.childrenWindows) delete obj.proto.childrenWindows
|
if (obj.proto.childrenWindows) delete obj.proto.childrenWindows
|
||||||
|
|||||||
@@ -18,3 +18,33 @@ import Chip from "./Chip"
|
|||||||
import ChipType from "./ChipType"
|
import ChipType from "./ChipType"
|
||||||
|
|
||||||
export const VISIBLE_CHIP = new Chip("V", "visible", ChipType.DEFAULT)
|
export const VISIBLE_CHIP = new Chip("V", "visible", ChipType.DEFAULT)
|
||||||
|
|
||||||
|
export const RELATIVE_Z_CHIP = {
|
||||||
|
short: 'RelZ',
|
||||||
|
long: 'Is relative Z-ordered to another surface',
|
||||||
|
class: 'warn',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RELATIVE_Z_PARENT_CHIP = {
|
||||||
|
short: 'RelZParent',
|
||||||
|
long: 'Something is relative Z-ordered to this surface',
|
||||||
|
class: 'warn',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MISSING_LAYER = {
|
||||||
|
short: 'MissingLayer',
|
||||||
|
long: 'This layer was referenced from the parent, but not present in the trace',
|
||||||
|
class: 'error',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GPU_CHIP = {
|
||||||
|
short: 'GPU',
|
||||||
|
long: 'This layer was composed on the GPU',
|
||||||
|
class: 'gpu',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HWC_CHIP = {
|
||||||
|
short: 'HWC',
|
||||||
|
long: 'This layer was composed by Hardware Composer',
|
||||||
|
class: 'hwc',
|
||||||
|
};
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import Chip from './Chip'
|
|
||||||
|
|
||||||
export type TreeViewObject = {
|
|
||||||
kind: String
|
|
||||||
name: String
|
|
||||||
shortName: String
|
|
||||||
stableId: String | Number
|
|
||||||
chips: Chip[]
|
|
||||||
obj: any
|
|
||||||
children: TreeViewObject[]
|
|
||||||
ref: any
|
|
||||||
}
|
|
||||||
@@ -14,23 +14,22 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPropertiesForDisplay, shortenName } from '../mixin'
|
import { shortenName } from '../mixin'
|
||||||
import { asRawTreeViewObject } from '../../utils/diff.js'
|
|
||||||
import { Activity } from "../common"
|
import { Activity } from "../common"
|
||||||
import WindowContainer from "./WindowContainer"
|
import WindowContainer from "./WindowContainer"
|
||||||
|
|
||||||
Activity.fromProto = function (proto): Activity {
|
Activity.fromProto = function (proto: any): Activity {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
} else {
|
} else {
|
||||||
const children = proto.windowToken.windowContainer.children.reverse()
|
const windowContainer = WindowContainer.fromProto(
|
||||||
.filter(it => it != null)
|
/* proto */ proto.windowToken.windowContainer,
|
||||||
.map(it => WindowContainer.childrenFromProto(it, /* isActivityInTree */ true))
|
/* protoChildren */ proto.windowToken.windowContainer.children.reverse(),
|
||||||
const windowContainer = WindowContainer.fromProto({proto: proto.windowToken.windowContainer,
|
/* isActivityInTree */ true,
|
||||||
children: children, identifierOverride: proto.identifier})
|
/* nameOverride */ null,
|
||||||
if (windowContainer == null) {
|
/* identifierOverride */ proto.identifier
|
||||||
throw "Window container should not be null: " + JSON.stringify(proto)
|
);
|
||||||
}
|
|
||||||
const entry = new Activity(
|
const entry = new Activity(
|
||||||
proto.name,
|
proto.name,
|
||||||
proto.state,
|
proto.state,
|
||||||
@@ -39,16 +38,18 @@ Activity.fromProto = function (proto): Activity {
|
|||||||
proto.procId,
|
proto.procId,
|
||||||
proto.translucent,
|
proto.translucent,
|
||||||
windowContainer
|
windowContainer
|
||||||
)
|
);
|
||||||
|
|
||||||
entry.obj = getPropertiesForDisplay(proto, entry)
|
addAttributes(entry, proto);
|
||||||
entry.kind = entry.constructor.name
|
console.warn("Created ", entry.kind, " stableId=", entry.stableId);
|
||||||
entry.shortName = shortenName(entry.name)
|
return entry;
|
||||||
entry.rawTreeViewObject = asRawTreeViewObject(entry)
|
|
||||||
|
|
||||||
console.warn("Created ", entry.kind, " stableId=", entry.stableId)
|
|
||||||
return entry
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Activity
|
function addAttributes(entry: Activity, proto: any) {
|
||||||
|
entry.proto = proto;
|
||||||
|
entry.kind = entry.constructor.name;
|
||||||
|
entry.shortName = shortenName(entry.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Activity;
|
||||||
|
|||||||
@@ -14,33 +14,33 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPropertiesForDisplay, shortenName } from '../mixin'
|
import { shortenName } from '../mixin'
|
||||||
import { asRawTreeViewObject } from '../../utils/diff.js'
|
|
||||||
import { DisplayArea } from "../common"
|
import { DisplayArea } from "../common"
|
||||||
import WindowContainer from "./WindowContainer"
|
import WindowContainer from "./WindowContainer"
|
||||||
|
|
||||||
DisplayArea.fromProto = function (proto, isActivityInTree: Boolean): DisplayArea {
|
DisplayArea.fromProto = function (proto: any, isActivityInTree: Boolean): DisplayArea {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
} else {
|
} else {
|
||||||
const children = proto.windowContainer.children.reverse()
|
const windowContainer = WindowContainer.fromProto(
|
||||||
.filter(it => it != null)
|
/* proto */ proto.windowContainer,
|
||||||
.map(it => WindowContainer.childrenFromProto(it, isActivityInTree))
|
/* protoChildren */ proto.windowContainer.children.reverse(),
|
||||||
const windowContainer = WindowContainer.fromProto({proto: proto.windowContainer,
|
/* isActivityInTree */ isActivityInTree,
|
||||||
children: children, nameOverride: proto.name})
|
/* nameOverride */ proto.name
|
||||||
if (windowContainer == null) {
|
);
|
||||||
throw "Window container should not be null: " + JSON.stringify(proto)
|
|
||||||
}
|
|
||||||
const entry = new DisplayArea(proto.isTaskDisplayArea, windowContainer)
|
|
||||||
|
|
||||||
entry.obj = getPropertiesForDisplay(proto, entry)
|
const entry = new DisplayArea(proto.isTaskDisplayArea, windowContainer);
|
||||||
entry.kind = entry.constructor.name
|
|
||||||
entry.shortName = shortenName(entry.name)
|
|
||||||
entry.rawTreeViewObject = asRawTreeViewObject(entry)
|
|
||||||
|
|
||||||
console.warn("Created ", entry.kind, " stableId=", entry.stableId)
|
addAttributes(entry, proto);
|
||||||
return entry
|
console.warn("Created ", entry.kind, " stableId=", entry.stableId);
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DisplayArea
|
function addAttributes(entry: DisplayArea, proto: any) {
|
||||||
|
entry.proto = proto;
|
||||||
|
entry.kind = entry.constructor.name;
|
||||||
|
entry.shortName = shortenName(entry.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DisplayArea;
|
||||||
|
|||||||
@@ -14,31 +14,26 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPropertiesForDisplay, shortenName } from '../mixin'
|
import { shortenName } from '../mixin'
|
||||||
import { asRawTreeViewObject } from '../../utils/diff.js'
|
|
||||||
import { toRect, DisplayContent, Rect } from "../common"
|
import { toRect, DisplayContent, Rect } from "../common"
|
||||||
import WindowContainer from "./WindowContainer"
|
import WindowContainer from "./WindowContainer"
|
||||||
|
|
||||||
DisplayContent.fromProto = function (proto, isActivityInTree: Boolean): DisplayContent {
|
DisplayContent.fromProto = function (proto: any, isActivityInTree: Boolean): DisplayContent {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
} else {
|
} else {
|
||||||
const children = proto.rootDisplayArea.windowContainer.children.reverse()
|
const windowContainer = WindowContainer.fromProto(
|
||||||
.filter(it => it != null)
|
/* proto */ proto.rootDisplayArea.windowContainer,
|
||||||
.map(it => WindowContainer.childrenFromProto(it, isActivityInTree))
|
/* protoChildren */ proto.rootDisplayArea.windowContainer.children.reverse(),
|
||||||
const windowContainer = WindowContainer.fromProto({proto: proto.rootDisplayArea.windowContainer,
|
/* isActivityInTree */ isActivityInTree,
|
||||||
children: children, nameOverride: proto.displayInfo?.name ?? null})
|
/* nameOverride */ proto.displayInfo?.name ?? null
|
||||||
if (windowContainer == null) {
|
);
|
||||||
throw "Window container should not be null: " + JSON.stringify(proto)
|
const displayRectWidth = proto.displayInfo?.logicalWidth ?? 0;
|
||||||
}
|
const displayRectHeight = proto.displayInfo?.logicalHeight ?? 0;
|
||||||
|
const appRectWidth = proto.displayInfo?.appWidth ?? 0;
|
||||||
const displayRectWidth = proto.displayInfo?.logicalWidth ?? 0
|
const appRectHeight = proto.displayInfo?.appHeight ?? 0;
|
||||||
const displayRectHeight = proto.displayInfo?.logicalHeight ?? 0
|
const defaultBounds = proto.pinnedStackController?.defaultBounds ?? null;
|
||||||
const appRectWidth = proto.displayInfo?.appWidth ?? 0
|
const movementBounds = proto.pinnedStackController?.movementBounds ?? null;
|
||||||
const appRectHeight = proto.displayInfo?.appHeight ?? 0
|
|
||||||
|
|
||||||
const defaultBounds = proto.pinnedStackController?.defaultBounds ?? null
|
|
||||||
const movementBounds = proto.pinnedStackController?.movementBounds ?? null
|
|
||||||
|
|
||||||
const entry = new DisplayContent(
|
const entry = new DisplayContent(
|
||||||
proto.id,
|
proto.id,
|
||||||
@@ -59,16 +54,18 @@ DisplayContent.fromProto = function (proto, isActivityInTree: Boolean): DisplayC
|
|||||||
proto.displayRotation?.rotation ?? 0,
|
proto.displayRotation?.rotation ?? 0,
|
||||||
proto.displayRotation?.lastOrientation ?? 0,
|
proto.displayRotation?.lastOrientation ?? 0,
|
||||||
windowContainer
|
windowContainer
|
||||||
)
|
);
|
||||||
|
|
||||||
entry.obj = getPropertiesForDisplay(proto, entry)
|
addAttributes(entry, proto);
|
||||||
entry.kind = entry.constructor.name
|
console.warn("Created ", entry.kind, " stableId=", entry.stableId);
|
||||||
entry.shortName = shortenName(entry.name)
|
return entry;
|
||||||
entry.rawTreeViewObject = asRawTreeViewObject(entry)
|
|
||||||
|
|
||||||
console.warn("Created ", entry.kind, " stableId=", entry.stableId)
|
|
||||||
return entry
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DisplayContent
|
function addAttributes(entry: DisplayContent, proto: any) {
|
||||||
|
entry.proto = proto;
|
||||||
|
entry.kind = entry.constructor.name;
|
||||||
|
entry.shortName = shortenName(entry.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DisplayContent;
|
||||||
|
|||||||
@@ -14,24 +14,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPropertiesForDisplay, shortenName } from '../mixin'
|
import { shortenName } from '../mixin'
|
||||||
import { asRawTreeViewObject } from '../../utils/diff.js'
|
|
||||||
import { Task, toRect } from "../common"
|
import { Task, toRect } from "../common"
|
||||||
import WindowContainer from "./WindowContainer"
|
import WindowContainer from "./WindowContainer"
|
||||||
|
|
||||||
Task.fromProto = function (proto, isActivityInTree: Boolean): Task {
|
Task.fromProto = function (proto: any, isActivityInTree: Boolean): Task {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
} else {
|
} else {
|
||||||
const windowContainerProto = proto.taskFragment?.windowContainer ?? proto.windowContainer
|
const windowContainerProto = proto.taskFragment?.windowContainer ?? proto.windowContainer;
|
||||||
const children = windowContainerProto.children.reverse()
|
const windowContainer = WindowContainer.fromProto(
|
||||||
.filter(it => it != null)
|
/* proto */ windowContainerProto,
|
||||||
.map(it => WindowContainer.childrenFromProto(it, isActivityInTree))
|
/* protoChildren */ windowContainerProto.children.reverse(),
|
||||||
const windowContainer = WindowContainer.fromProto({proto: windowContainerProto,
|
/* isActivityInTree */ isActivityInTree
|
||||||
children: children})
|
);
|
||||||
if (windowContainer == null) {
|
|
||||||
throw "Window container should not be null: " + JSON.stringify(proto)
|
|
||||||
}
|
|
||||||
const entry = new Task(
|
const entry = new Task(
|
||||||
proto.taskFragment?.activityType ?? proto.activityType,
|
proto.taskFragment?.activityType ?? proto.activityType,
|
||||||
proto.fillsParent,
|
proto.fillsParent,
|
||||||
@@ -51,16 +48,18 @@ Task.fromProto = function (proto, isActivityInTree: Boolean): Task {
|
|||||||
proto.taskFragment?.minWidth ?? proto.minWidth,
|
proto.taskFragment?.minWidth ?? proto.minWidth,
|
||||||
proto.taskFragment?.minHeight ?? proto.minHeight,
|
proto.taskFragment?.minHeight ?? proto.minHeight,
|
||||||
windowContainer
|
windowContainer
|
||||||
)
|
);
|
||||||
|
|
||||||
entry.obj = getPropertiesForDisplay(proto, entry)
|
addAttributes(entry, proto);
|
||||||
entry.kind = entry.constructor.name
|
console.warn("Created ", entry.kind, " stableId=", entry.stableId);
|
||||||
entry.shortName = shortenName(entry.name)
|
return entry;
|
||||||
entry.rawTreeViewObject = asRawTreeViewObject(entry)
|
|
||||||
|
|
||||||
console.warn("Created ", entry.kind, " stableId=", entry.stableId)
|
|
||||||
return entry
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Task
|
function addAttributes(entry: Task, proto: any) {
|
||||||
|
entry.proto = proto;
|
||||||
|
entry.kind = entry.constructor.name;
|
||||||
|
entry.shortName = shortenName(entry.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Task;
|
||||||
|
|||||||
@@ -14,39 +14,36 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPropertiesForDisplay, shortenName } from '../mixin'
|
import { shortenName } from '../mixin'
|
||||||
import { asRawTreeViewObject } from '../../utils/diff.js'
|
|
||||||
import { TaskFragment } from "../common"
|
import { TaskFragment } from "../common"
|
||||||
import WindowContainer from "./WindowContainer"
|
import WindowContainer from "./WindowContainer"
|
||||||
|
|
||||||
TaskFragment.fromProto = function (proto, isActivityInTree: Boolean): TaskFragment {
|
TaskFragment.fromProto = function (proto: any, isActivityInTree: Boolean): TaskFragment {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
} else {
|
} else {
|
||||||
const children = proto.windowContainer.children.reverse()
|
const windowContainer = WindowContainer.fromProto(
|
||||||
.filter(it => it != null)
|
/* proto */ proto.windowContainer,
|
||||||
.map(it => WindowContainer.childrenFromProto(it, isActivityInTree))
|
/* protoChildren */ proto.windowContainer.children.reverse(),
|
||||||
const windowContainer = WindowContainer.fromProto({proto: proto.windowContainer,
|
/* isActivityInTree */ isActivityInTree);
|
||||||
children: children})
|
|
||||||
if (windowContainer == null) {
|
|
||||||
throw "Window container should not be null: " + JSON.stringify(proto)
|
|
||||||
}
|
|
||||||
const entry = new TaskFragment(
|
const entry = new TaskFragment(
|
||||||
proto.activityType,
|
proto.activityType,
|
||||||
proto.displayId,
|
proto.displayId,
|
||||||
proto.minWidth,
|
proto.minWidth,
|
||||||
proto.minHeight,
|
proto.minHeight,
|
||||||
windowContainer
|
windowContainer
|
||||||
)
|
);
|
||||||
|
|
||||||
entry.obj = getPropertiesForDisplay(proto, entry)
|
addAttributes(entry, proto);
|
||||||
entry.kind = entry.constructor.name
|
console.warn("Created ", entry.kind, " stableId=", entry.stableId);
|
||||||
entry.shortName = shortenName(entry.name)
|
return entry;
|
||||||
entry.rawTreeViewObject = asRawTreeViewObject(entry)
|
|
||||||
|
|
||||||
console.warn("Created ", entry.kind, " stableId=", entry.stableId)
|
|
||||||
return entry
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TaskFragment
|
function addAttributes(entry: TaskFragment, proto: any) {
|
||||||
|
entry.proto = proto;
|
||||||
|
entry.kind = entry.constructor.name;
|
||||||
|
entry.shortName = shortenName(entry.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TaskFragment;
|
||||||
|
|||||||
@@ -14,8 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPropertiesForDisplay, shortenName } from '../mixin'
|
import { shortenName } from '../mixin'
|
||||||
import { asRawTreeViewObject } from '../../utils/diff.js'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Configuration,
|
Configuration,
|
||||||
@@ -34,21 +33,27 @@ import TaskFragment from "./TaskFragment"
|
|||||||
import WindowState from "./WindowState"
|
import WindowState from "./WindowState"
|
||||||
import WindowToken from "./WindowToken"
|
import WindowToken from "./WindowToken"
|
||||||
|
|
||||||
WindowContainer.fromProto = function ({
|
WindowContainer.fromProto = function (
|
||||||
proto,
|
proto: any,
|
||||||
children,
|
protoChildren: any[],
|
||||||
nameOverride = null,
|
isActivityInTree: boolean,
|
||||||
identifierOverride = null,
|
nameOverride: string = null,
|
||||||
tokenOverride = null
|
identifierOverride: string = null,
|
||||||
}): WindowContainer {
|
tokenOverride = null,
|
||||||
|
): WindowContainer {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
const identifier = identifierOverride ?? proto.identifier
|
|
||||||
var name = nameOverride ?? identifier?.title ?? ""
|
|
||||||
var token = tokenOverride?.toString(16) ?? identifier?.hashCode?.toString(16) ?? ""
|
|
||||||
|
|
||||||
const config = newConfigurationContainer(proto.configurationContainer)
|
const children = protoChildren
|
||||||
|
.filter(it => it != null)
|
||||||
|
.map(it => WindowContainer.childrenFromProto(it, isActivityInTree));
|
||||||
|
|
||||||
|
const identifier = identifierOverride ?? proto.identifier;
|
||||||
|
var name = nameOverride ?? identifier?.title ?? "";
|
||||||
|
var token = tokenOverride?.toString(16) ?? identifier?.hashCode?.toString(16) ?? "";
|
||||||
|
|
||||||
|
const config = createConfigurationContainer(proto.configurationContainer);
|
||||||
const entry = new WindowContainer(
|
const entry = new WindowContainer(
|
||||||
name,
|
name,
|
||||||
token,
|
token,
|
||||||
@@ -56,19 +61,19 @@ WindowContainer.fromProto = function ({
|
|||||||
proto.visible,
|
proto.visible,
|
||||||
config,
|
config,
|
||||||
children
|
children
|
||||||
)
|
);
|
||||||
|
|
||||||
// we remove the children property from the object to avoid it showing the
|
addAttributes(entry, proto);
|
||||||
// the properties view of the element as we can always see those elements'
|
return entry;
|
||||||
// properties by changing the target element in the hierarchy tree view.
|
|
||||||
entry.obj = getPropertiesForDisplay(proto, entry)
|
|
||||||
entry.kind = entry.constructor.name
|
|
||||||
entry.shortName = shortenName(entry.name)
|
|
||||||
entry.rawTreeViewObject = asRawTreeViewObject(entry)
|
|
||||||
return entry
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowContainer.childrenFromProto = function(proto, isActivityInTree: Boolean): WindowContainerChild {
|
function addAttributes(entry: WindowContainer, proto: any) {
|
||||||
|
entry.proto = proto;
|
||||||
|
entry.kind = entry.constructor.name;
|
||||||
|
entry.shortName = shortenName(entry.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowContainer.childrenFromProto = function(proto: any, isActivityInTree: Boolean): WindowContainerChild {
|
||||||
return DisplayContent.fromProto(proto.displayContent, isActivityInTree) ??
|
return DisplayContent.fromProto(proto.displayContent, isActivityInTree) ??
|
||||||
DisplayArea.fromProto(proto.displayArea, isActivityInTree) ??
|
DisplayArea.fromProto(proto.displayArea, isActivityInTree) ??
|
||||||
Task.fromProto(proto.task, isActivityInTree) ??
|
Task.fromProto(proto.task, isActivityInTree) ??
|
||||||
@@ -76,28 +81,28 @@ WindowContainer.childrenFromProto = function(proto, isActivityInTree: Boolean):
|
|||||||
Activity.fromProto(proto.activity) ??
|
Activity.fromProto(proto.activity) ??
|
||||||
WindowToken.fromProto(proto.windowToken, isActivityInTree) ??
|
WindowToken.fromProto(proto.windowToken, isActivityInTree) ??
|
||||||
WindowState.fromProto(proto.window, isActivityInTree) ??
|
WindowState.fromProto(proto.window, isActivityInTree) ??
|
||||||
WindowContainer.fromProto({proto: proto.windowContainer})
|
WindowContainer.fromProto(proto.windowContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
function newConfigurationContainer(proto): ConfigurationContainer {
|
function createConfigurationContainer(proto: any): ConfigurationContainer {
|
||||||
const entry = new ConfigurationContainer(
|
const entry = new ConfigurationContainer(
|
||||||
newConfiguration(proto?.overrideConfiguration ?? null),
|
createConfiguration(proto?.overrideConfiguration ?? null),
|
||||||
newConfiguration(proto?.fullConfiguration ?? null),
|
createConfiguration(proto?.fullConfiguration ?? null),
|
||||||
newConfiguration(proto?.mergedOverrideConfiguration ?? null)
|
createConfiguration(proto?.mergedOverrideConfiguration ?? null)
|
||||||
)
|
);
|
||||||
|
|
||||||
entry.obj = entry
|
entry.obj = entry;
|
||||||
return entry
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
function newConfiguration(proto): Configuration {
|
function createConfiguration(proto: any): Configuration {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
var windowConfiguration = null
|
var windowConfiguration = null;
|
||||||
|
|
||||||
if (proto != null && proto.windowConfiguration != null) {
|
if (proto != null && proto.windowConfiguration != null) {
|
||||||
windowConfiguration = newWindowConfiguration(proto.windowConfiguration)
|
windowConfiguration = createWindowConfiguration(proto.windowConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Configuration(
|
return new Configuration(
|
||||||
@@ -109,17 +114,17 @@ function newConfiguration(proto): Configuration {
|
|||||||
proto?.smallestScreenWidthDp ?? 0,
|
proto?.smallestScreenWidthDp ?? 0,
|
||||||
proto?.screenLayout ?? 0,
|
proto?.screenLayout ?? 0,
|
||||||
proto?.uiMode ?? 0
|
proto?.uiMode ?? 0
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function newWindowConfiguration(proto): WindowConfiguration {
|
function createWindowConfiguration(proto: any): WindowConfiguration {
|
||||||
return new WindowConfiguration(
|
return new WindowConfiguration(
|
||||||
toRect(proto.appBounds),
|
toRect(proto.appBounds),
|
||||||
toRect(proto.bounds),
|
toRect(proto.bounds),
|
||||||
toRect(proto.maxBounds),
|
toRect(proto.maxBounds),
|
||||||
proto.windowingMode,
|
proto.windowingMode,
|
||||||
proto.activityType
|
proto.activityType
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WindowContainer
|
export default WindowContainer;
|
||||||
|
|||||||
@@ -14,55 +14,35 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPropertiesForDisplay, shortenName } from '../mixin'
|
import { shortenName } from '../mixin'
|
||||||
import { asRawTreeViewObject } from '../../utils/diff.js'
|
import { toRect, Size, WindowState, WindowLayoutParams } from "../common"
|
||||||
import { toRect, Bounds, WindowState, WindowLayoutParams } from "../common"
|
|
||||||
import { VISIBLE_CHIP } from '../treeview/Chips'
|
import { VISIBLE_CHIP } from '../treeview/Chips'
|
||||||
import WindowContainer from "./WindowContainer"
|
import WindowContainer from "./WindowContainer"
|
||||||
|
|
||||||
WindowState.fromProto = function (proto, isActivityInTree: Boolean): WindowState {
|
WindowState.fromProto = function (proto: any, isActivityInTree: Boolean): WindowState {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
} else {
|
} else {
|
||||||
const identifierName = proto.windowContainer.identifier?.title ?? proto.identifier?.title ?? ""
|
const windowParams = createWindowLayoutParams(proto.attributes);
|
||||||
var windowType = 0
|
const identifierName = getIdentifier(proto);
|
||||||
if (identifierName.startsWith(WindowState.STARTING_WINDOW_PREFIX)) {
|
const windowType = getWindowType(proto, identifierName);
|
||||||
windowType = WindowState.WINDOW_TYPE_STARTING
|
const name = getName(identifierName);
|
||||||
} else if (proto.animatingExit) {
|
const windowContainer = WindowContainer.fromProto(
|
||||||
windowType = WindowState.WINDOW_TYPE_EXITING
|
/* proto */ proto.windowContainer,
|
||||||
} else if (identifierName.startsWith(WindowState.DEBUGGER_WINDOW_PREFIX)) {
|
/* protoChildren */ proto.windowContainer.children.reverse(),
|
||||||
windowType = WindowState.WINDOW_TYPE_STARTING
|
/* isActivityInTree */ isActivityInTree,
|
||||||
}
|
/* nameOverride */ name,
|
||||||
|
/* identifierOverride */ proto.identifier
|
||||||
var nameOverride = identifierName
|
);
|
||||||
|
|
||||||
if (identifierName.startsWith(WindowState.STARTING_WINDOW_PREFIX)) {
|
|
||||||
nameOverride = identifierName.substring(WindowState.STARTING_WINDOW_PREFIX.length)
|
|
||||||
} else if (identifierName.startsWith(WindowState.DEBUGGER_WINDOW_PREFIX)) {
|
|
||||||
nameOverride = identifierName.substring(WindowState.DEBUGGER_WINDOW_PREFIX.length)
|
|
||||||
}
|
|
||||||
|
|
||||||
const children = proto.windowContainer.children.reverse()
|
|
||||||
.filter(it => it != null)
|
|
||||||
.map(it => WindowContainer.childrenFromProto(it, isActivityInTree))
|
|
||||||
|
|
||||||
const windowContainer = WindowContainer.fromProto({
|
|
||||||
proto: proto.windowContainer,
|
|
||||||
children: children,
|
|
||||||
nameOverride: nameOverride,
|
|
||||||
identifierOverride: proto.identifier})
|
|
||||||
if (windowContainer == null) {
|
|
||||||
throw "Window container should not be null: " + JSON.stringify(proto)
|
|
||||||
}
|
|
||||||
|
|
||||||
const entry = new WindowState(
|
const entry = new WindowState(
|
||||||
newWindowLayoutParams(proto.attributes),
|
windowParams,
|
||||||
proto.displayId,
|
proto.displayId,
|
||||||
proto.stackId,
|
proto.stackId,
|
||||||
proto.animator?.surface?.layer ?? 0,
|
proto.animator?.surface?.layer ?? 0,
|
||||||
proto.animator?.surface?.shown ?? false,
|
proto.animator?.surface?.shown ?? false,
|
||||||
windowType,
|
windowType,
|
||||||
new Bounds(proto.requestedWidth, proto.requestedHeight),
|
new Size(proto.requestedWidth, proto.requestedHeight),
|
||||||
toRect(proto.surfacePosition),
|
toRect(proto.surfacePosition),
|
||||||
toRect(proto.windowFrames?.frame ?? null),
|
toRect(proto.windowFrames?.frame ?? null),
|
||||||
toRect(proto.windowFrames?.containingFrame ?? null),
|
toRect(proto.windowFrames?.containingFrame ?? null),
|
||||||
@@ -74,22 +54,14 @@ import WindowContainer from "./WindowContainer"
|
|||||||
toRect(proto.animator?.lastClipRect ?? null),
|
toRect(proto.animator?.lastClipRect ?? null),
|
||||||
windowContainer,
|
windowContainer,
|
||||||
/* isAppWindow */ isActivityInTree
|
/* isAppWindow */ isActivityInTree
|
||||||
)
|
);
|
||||||
|
|
||||||
entry.kind = entry.constructor.name
|
addAttributes(entry, proto);
|
||||||
entry.rect = entry.frame
|
return entry;
|
||||||
entry.rect.ref = entry
|
|
||||||
entry.rect.label = entry.name
|
|
||||||
entry.obj = getPropertiesForDisplay(proto, entry)
|
|
||||||
entry.shortName = shortenName(entry.name)
|
|
||||||
entry.visible = entry.isVisible ?? false
|
|
||||||
entry.chips = entry.isVisible ? [VISIBLE_CHIP] : []
|
|
||||||
entry.rawTreeViewObject = asRawTreeViewObject(entry)
|
|
||||||
return entry
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function newWindowLayoutParams(proto): WindowLayoutParams {
|
function createWindowLayoutParams(proto: any): WindowLayoutParams {
|
||||||
return new WindowLayoutParams(
|
return new WindowLayoutParams(
|
||||||
/* type */ proto?.type ?? 0,
|
/* type */ proto?.type ?? 0,
|
||||||
/* x */ proto?.x ?? 0,
|
/* x */ proto?.x ?? 0,
|
||||||
@@ -124,4 +96,42 @@ function newWindowLayoutParams(proto): WindowLayoutParams {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getWindowType(proto: any, identifierName: string): number {
|
||||||
|
if (identifierName.startsWith(WindowState.STARTING_WINDOW_PREFIX)) {
|
||||||
|
return WindowState.WINDOW_TYPE_STARTING;
|
||||||
|
} else if (proto.animatingExit) {
|
||||||
|
return WindowState.WINDOW_TYPE_EXITING;
|
||||||
|
} else if (identifierName.startsWith(WindowState.DEBUGGER_WINDOW_PREFIX)) {
|
||||||
|
return WindowState.WINDOW_TYPE_STARTING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getName(identifierName: string): string {
|
||||||
|
var name = identifierName;
|
||||||
|
|
||||||
|
if (identifierName.startsWith(WindowState.STARTING_WINDOW_PREFIX)) {
|
||||||
|
name = identifierName.substring(WindowState.STARTING_WINDOW_PREFIX.length);
|
||||||
|
} else if (identifierName.startsWith(WindowState.DEBUGGER_WINDOW_PREFIX)) {
|
||||||
|
name = identifierName.substring(WindowState.DEBUGGER_WINDOW_PREFIX.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIdentifier(proto: any): string {
|
||||||
|
return proto.windowContainer.identifier?.title ?? proto.identifier?.title ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function addAttributes(entry: WindowState, proto: any) {
|
||||||
|
entry.kind = entry.constructor.name;
|
||||||
|
entry.rect = entry.frame;
|
||||||
|
entry.rect.ref = entry;
|
||||||
|
entry.rect.label = entry.name;
|
||||||
|
entry.proto = proto;
|
||||||
|
entry.shortName = shortenName(entry.name);
|
||||||
|
entry.chips = entry.isVisible ? [VISIBLE_CHIP] : [];
|
||||||
|
}
|
||||||
|
|
||||||
export default WindowState
|
export default WindowState
|
||||||
|
|||||||
@@ -14,32 +14,29 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPropertiesForDisplay, shortenName } from '../mixin'
|
import { shortenName } from '../mixin'
|
||||||
import { asRawTreeViewObject } from '../../utils/diff.js'
|
|
||||||
import { WindowToken } from "../common"
|
import { WindowToken } from "../common"
|
||||||
import WindowContainer from "./WindowContainer"
|
import WindowContainer from "./WindowContainer"
|
||||||
|
|
||||||
WindowToken.fromProto = function (proto, isActivityInTree: Boolean): WindowToken {
|
WindowToken.fromProto = function (proto: any, isActivityInTree: Boolean): WindowToken {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const children = proto.windowContainer.children.reverse()
|
const windowContainer = WindowContainer.fromProto(
|
||||||
.filter(it => it != null)
|
/* proto */ proto.windowContainer,
|
||||||
.map(it => WindowContainer.childrenFromProto(it, isActivityInTree))
|
/* protoChildren */ proto.windowContainer.children.reverse(),
|
||||||
const windowContainer = WindowContainer.fromProto({proto: proto.windowContainer,
|
/* isActivityInTree */ isActivityInTree,
|
||||||
children: children, tokenOverride: proto.hashCode})
|
/* nameOverride */ null,
|
||||||
if (windowContainer == null) {
|
/* identifierOverride */ null,
|
||||||
throw "Window container should not be null: " + JSON.stringify(proto)
|
/* tokenOverride */ proto.hashCode
|
||||||
}
|
);
|
||||||
const entry = new WindowToken(windowContainer)
|
const entry = new WindowToken(windowContainer);
|
||||||
entry.kind = entry.constructor.name
|
entry.kind = entry.constructor.name;
|
||||||
entry.obj = getPropertiesForDisplay(proto, entry)
|
entry.proto = proto;
|
||||||
entry.shortName = shortenName(entry.name)
|
entry.shortName = shortenName(entry.name);
|
||||||
entry.rawTreeViewObject = asRawTreeViewObject(entry)
|
console.warn("Created ", entry.kind, " stableId=", entry.stableId);
|
||||||
|
return entry;
|
||||||
console.warn("Created ", entry.kind, " stableId=", entry.stableId)
|
|
||||||
return entry
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WindowToken
|
export default WindowToken;
|
||||||
|
|||||||
@@ -252,6 +252,9 @@ const store = new Vuex.Store({
|
|||||||
},
|
},
|
||||||
updateTimelineTime(context, timestamp) {
|
updateTimelineTime(context, timestamp) {
|
||||||
for (const file of context.getters.files) {
|
for (const file of context.getters.files) {
|
||||||
|
//dumps do not have a timeline, so only look at files with timelines to update the timestamp
|
||||||
|
if (!file.timeline) continue;
|
||||||
|
|
||||||
const type = file.type;
|
const type = file.type;
|
||||||
const entryIndex = findLastMatchingSorted(
|
const entryIndex = findLastMatchingSorted(
|
||||||
file.timeline,
|
file.timeline,
|
||||||
|
|||||||
@@ -14,198 +14,38 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* transform type flags */
|
function multiplyVec2(matrix, x, y) {
|
||||||
const TRANSLATE_VAL = 0x0001;
|
|
||||||
const ROTATE_VAL = 0x0002;
|
|
||||||
const SCALE_VAL = 0x0004;
|
|
||||||
|
|
||||||
/* orientation flags */
|
|
||||||
const FLIP_H_VAL = 0x0100; // (1 << 0 << 8)
|
|
||||||
const FLIP_V_VAL = 0x0200; // (1 << 1 << 8)
|
|
||||||
const ROT_90_VAL = 0x0400; // (1 << 2 << 8)
|
|
||||||
const ROT_INVALID_VAL = 0x8000; // (0x80 << 8)
|
|
||||||
|
|
||||||
function is_proto_2(transform) {
|
|
||||||
/*
|
|
||||||
* Checks if the loaded file was a stored with ProtoBuf2 or Protobuf3
|
|
||||||
*
|
|
||||||
* Proto2 files don't have a Type for the transform object but all other
|
|
||||||
* fields of the transform are set.
|
|
||||||
*
|
|
||||||
* Proto3 has a type field for the transform but doesn't store default
|
|
||||||
* values (0 for transform type), also, the framework/native implementation
|
|
||||||
* doesn't write a transform in case it is an identity matrix.
|
|
||||||
*/
|
|
||||||
var propertyNames = Object.getOwnPropertyNames(transform);
|
|
||||||
return (!propertyNames.includes("type") && propertyNames.includes("dsdx"));
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_simple_transform(transform) {
|
|
||||||
transform = transform || {};
|
|
||||||
if (is_proto_2(transform)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return is_type_flag_clear(transform, ROT_INVALID_VAL|SCALE_VAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a transform type into readable format.
|
|
||||||
* Adapted from the dump function from framework/native
|
|
||||||
*
|
|
||||||
* @param {*} transform Transform object ot be converter
|
|
||||||
*/
|
|
||||||
function format_transform_type(transform) {
|
|
||||||
if (is_proto_2(transform)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_type_flag_clear(transform, SCALE_VAL | ROTATE_VAL | TRANSLATE_VAL)) {
|
|
||||||
return "IDENTITY";
|
|
||||||
}
|
|
||||||
|
|
||||||
var type_flags = [];
|
|
||||||
if (is_type_flag_set(transform, SCALE_VAL)) {
|
|
||||||
type_flags.push("SCALE");
|
|
||||||
}
|
|
||||||
if (is_type_flag_set(transform, TRANSLATE_VAL)) {
|
|
||||||
type_flags.push("TRANSLATE");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_type_flag_set(transform, ROT_INVALID_VAL)) {
|
|
||||||
type_flags.push("ROT_INVALID");
|
|
||||||
} else if (is_type_flag_set(transform, ROT_90_VAL|FLIP_V_VAL|FLIP_H_VAL)) {
|
|
||||||
type_flags.push("ROT_270");
|
|
||||||
} else if (is_type_flag_set(transform, FLIP_V_VAL|FLIP_H_VAL)) {
|
|
||||||
type_flags.push("ROT_180");
|
|
||||||
} else {
|
|
||||||
if (is_type_flag_set(transform, ROT_90_VAL)) {
|
|
||||||
type_flags.push("ROT_90");
|
|
||||||
}
|
|
||||||
if (is_type_flag_set(transform, FLIP_V_VAL)) {
|
|
||||||
type_flags.push("FLIP_V");
|
|
||||||
}
|
|
||||||
if (is_type_flag_set(transform, FLIP_H_VAL)) {
|
|
||||||
type_flags.push("FLIP_H");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type_flags.length == 0) {
|
|
||||||
throw "Unknown transform type " + transform ;
|
|
||||||
}
|
|
||||||
|
|
||||||
return type_flags.join(', ');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures all values of the transform object are set.
|
|
||||||
*/
|
|
||||||
function fill_transform_data(transform) {
|
|
||||||
function fill_simple_transform(transform) {
|
|
||||||
// ROT_270 = ROT_90|FLIP_H|FLIP_V;
|
|
||||||
if (is_type_flag_set(transform, ROT_90_VAL|FLIP_V_VAL|FLIP_H_VAL)) {
|
|
||||||
transform.dsdx = 0.0;
|
|
||||||
transform.dtdx = -1.0;
|
|
||||||
transform.dsdy = 1.0;
|
|
||||||
transform.dtdy = 0.0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ROT_180 = FLIP_H|FLIP_V;
|
|
||||||
if (is_type_flag_set(transform, FLIP_V_VAL|FLIP_H_VAL)) {
|
|
||||||
transform.dsdx = -1.0;
|
|
||||||
transform.dtdx = 0.0;
|
|
||||||
transform.dsdy = 0.0;
|
|
||||||
transform.dtdy = -1.0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ROT_90
|
|
||||||
if (is_type_flag_set(transform, ROT_90_VAL)) {
|
|
||||||
transform.dsdx = 0.0;
|
|
||||||
transform.dtdx = 1.0;
|
|
||||||
transform.dsdy = -1.0;
|
|
||||||
transform.dtdy = 0.0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IDENTITY
|
|
||||||
if (is_type_flag_clear(transform, SCALE_VAL | ROTATE_VAL)) {
|
|
||||||
transform.dsdx = 1.0;
|
|
||||||
transform.dtdx = 0.0;
|
|
||||||
transform.dsdy = 0.0;
|
|
||||||
transform.dtdy = 1.0;
|
|
||||||
transform.type = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw "Unknown transform type " + transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!transform) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_proto_2(transform)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_simple_transform(transform)){
|
|
||||||
fill_simple_transform(transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
transform.dsdx = transform.dsdx || 0.0;
|
|
||||||
transform.dtdx = transform.dtdx || 0.0;
|
|
||||||
transform.dsdy = transform.dsdy || 0.0;
|
|
||||||
transform.dtdy = transform.dtdy || 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_type_flag_set(transform, bits) {
|
|
||||||
transform = transform || {};
|
|
||||||
var type = transform.type || 0;
|
|
||||||
return (type & bits) === bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_type_flag_clear(transform, bits) {
|
|
||||||
transform = transform || {};
|
|
||||||
var type = transform.type || 0;
|
|
||||||
return (type & bits) === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function multiply_vec2(matrix, x, y) {
|
|
||||||
if (!matrix) return {x, y};
|
if (!matrix) return {x, y};
|
||||||
// |dsdx dsdy tx| | x |
|
// |dsdx dsdy tx| | x |
|
||||||
// |dtdx dtdy ty| x | y |
|
// |dtdx dtdy ty| x | y |
|
||||||
// |0 0 1 | | 1 |
|
// |0 0 1 | | 1 |
|
||||||
return {
|
return {
|
||||||
x: matrix.dsdx * x + matrix.dsdy * y + matrix.tx,
|
x: matrix.dsdx * x + matrix.dsdy * y + matrix.tx,
|
||||||
y: matrix.dtdx * x + matrix.dtdy * y + matrix.ty
|
y: matrix.dtdx * x + matrix.dtdy * y + matrix.ty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function multiply_rect(matrix, rect) {
|
function multiplyRect(transform, rect) {
|
||||||
|
let matrix = transform;
|
||||||
|
if (transform && transform.matrix) {
|
||||||
|
matrix = transform.matrix;
|
||||||
|
}
|
||||||
// |dsdx dsdy tx| | left, top |
|
// |dsdx dsdy tx| | left, top |
|
||||||
// matrix = |dtdx dtdy ty| rect = | |
|
// matrix = |dtdx dtdy ty| rect = | |
|
||||||
// |0 0 1 | | right, bottom |
|
// |0 0 1 | | right, bottom |
|
||||||
|
|
||||||
var left_top = multiply_vec2(matrix, rect.left, rect.top);
|
const leftTop = multiplyVec2(matrix, rect.left, rect.top);
|
||||||
var right_top = multiply_vec2(matrix, rect.right, rect.top);
|
const rightTop = multiplyVec2(matrix, rect.right, rect.top);
|
||||||
var left_bottom = multiply_vec2(matrix, rect.left, rect.bottom);
|
const leftBottom = multiplyVec2(matrix, rect.left, rect.bottom);
|
||||||
var right_bottom = multiply_vec2(matrix, rect.right, rect.bottom);
|
const rightBottom = multiplyVec2(matrix, rect.right, rect.bottom);
|
||||||
|
|
||||||
var outrect = {};
|
const outrect = {};
|
||||||
outrect.left = Math.min(left_top.x, right_top.x, left_bottom.x, right_bottom.x);
|
outrect.left = Math.min(leftTop.x, rightTop.x, leftBottom.x, rightBottom.x);
|
||||||
outrect.top = Math.min(left_top.y, right_top.y, left_bottom.y, right_bottom.y);
|
outrect.top = Math.min(leftTop.y, rightTop.y, leftBottom.y, rightBottom.y);
|
||||||
outrect.right = Math.max(left_top.x, right_top.x, left_bottom.x, right_bottom.x);
|
outrect.right = Math.max(leftTop.x, rightTop.x, leftBottom.x, rightBottom.x);
|
||||||
outrect.bottom = Math.max(left_top.y, right_top.y, left_bottom.y, right_bottom.y);
|
outrect.bottom = Math.max(leftTop.y, rightTop.y, leftBottom.y,
|
||||||
|
rightBottom.y);
|
||||||
return outrect;
|
return outrect;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the applying the transform on an an axis aligned rectangle
|
export {multiplyRect};
|
||||||
// results in another axis aligned rectangle.
|
|
||||||
function is_simple_rotation(transform) {
|
|
||||||
return !is_type_flag_set(transform, ROT_INVALID_VAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
export {format_transform_type, fill_transform_data, is_simple_transform,
|
|
||||||
multiply_rect, is_simple_rotation};
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {TRACE_TYPES, DUMP_TYPES} from '@/decode.js';
|
|||||||
const mixin = {
|
const mixin = {
|
||||||
showInTraceView(file) {
|
showInTraceView(file) {
|
||||||
return file.type == TRACE_TYPES.WINDOW_MANAGER ||
|
return file.type == TRACE_TYPES.WINDOW_MANAGER ||
|
||||||
|
file.type == TRACE_TYPES.ACCESSIBILITY ||
|
||||||
file.type == TRACE_TYPES.SURFACE_FLINGER ||
|
file.type == TRACE_TYPES.SURFACE_FLINGER ||
|
||||||
file.type == TRACE_TYPES.WAYLAND ||
|
file.type == TRACE_TYPES.WAYLAND ||
|
||||||
file.type == TRACE_TYPES.SYSTEM_UI ||
|
file.type == TRACE_TYPES.SYSTEM_UI ||
|
||||||
@@ -30,6 +31,9 @@ const mixin = {
|
|||||||
file.type == DUMP_TYPES.SURFACE_FLINGER ||
|
file.type == DUMP_TYPES.SURFACE_FLINGER ||
|
||||||
file.type == DUMP_TYPES.WAYLAND;
|
file.type == DUMP_TYPES.WAYLAND;
|
||||||
},
|
},
|
||||||
|
showInAccessibilityTraceView(file) {
|
||||||
|
return file.type == TRACE_TYPES.ACCESSIBILITY;
|
||||||
|
},
|
||||||
showInWindowManagerTraceView(file) {
|
showInWindowManagerTraceView(file) {
|
||||||
return file.type == TRACE_TYPES.WINDOW_MANAGER ||
|
return file.type == TRACE_TYPES.WINDOW_MANAGER ||
|
||||||
file.type == DUMP_TYPES.WINDOW_MANAGER;
|
file.type == DUMP_TYPES.WINDOW_MANAGER;
|
||||||
|
|||||||
@@ -229,7 +229,14 @@ export default {
|
|||||||
if (this.disabled) {
|
if (this.disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const timestamp = parseInt(this.timeline[clickedOnTsIndex]);
|
|
||||||
|
var timestamp = parseInt(this.timeline[clickedOnTsIndex]);
|
||||||
|
|
||||||
|
//pointWidth is always 1
|
||||||
|
//if offset percentage < 1, clickedOnTsIndex becomes negative, leading to a negative index
|
||||||
|
if (clickedOnTsIndex < 0) {
|
||||||
|
timestamp = parseInt(this.timeline[0])
|
||||||
|
}
|
||||||
this.$store.dispatch('updateTimelineTime', timestamp);
|
this.$store.dispatch('updateTimelineTime', timestamp);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,350 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class for deriving state and visibility from the hierarchy. This
|
|
||||||
* duplicates some of the logic in surface flinger. If the trace contains
|
|
||||||
* composition state (visibleRegion), it will be used otherwise it will be
|
|
||||||
* derived.
|
|
||||||
*/
|
|
||||||
import {multiply_rect, is_simple_rotation} from './matrix_utils.js';
|
|
||||||
|
|
||||||
// Layer flags
|
|
||||||
const FLAG_HIDDEN = 0x01;
|
|
||||||
const FLAG_OPAQUE = 0x02;
|
|
||||||
const FLAG_SECURE = 0x80;
|
|
||||||
|
|
||||||
function flags_to_string(flags) {
|
|
||||||
if (!flags) return '';
|
|
||||||
const verboseFlags = [];
|
|
||||||
if (flags & FLAG_HIDDEN) verboseFlags.push('HIDDEN');
|
|
||||||
if (flags & FLAG_OPAQUE) verboseFlags.push('OPAQUE');
|
|
||||||
if (flags & FLAG_SECURE) verboseFlags.push('SECURE');
|
|
||||||
return verboseFlags.join('|') + ' (' + flags + ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_empty(region) {
|
|
||||||
return region == undefined ||
|
|
||||||
region.rect == undefined ||
|
|
||||||
region.rect.length == 0 ||
|
|
||||||
region.rect.every(function(r) {
|
|
||||||
return is_empty_rect(r);
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_empty_rect(rect) {
|
|
||||||
const right = rect.right || 0;
|
|
||||||
const left = rect.left || 0;
|
|
||||||
const top = rect.top || 0;
|
|
||||||
const bottom = rect.bottom || 0;
|
|
||||||
|
|
||||||
return (right - left) <= 0 || (bottom - top) <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_rect_empty_and_valid(rect) {
|
|
||||||
return rect &&
|
|
||||||
(rect.left - rect.right === 0 || rect.top - rect.bottom === 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The transformation matrix is defined as the product of:
|
|
||||||
* | cos(a) -sin(a) | \/ | X 0 |
|
|
||||||
* | sin(a) cos(a) | /\ | 0 Y |
|
|
||||||
*
|
|
||||||
* where a is a rotation angle, and X and Y are scaling factors.
|
|
||||||
* A transformation matrix is invalid when either X or Y is zero,
|
|
||||||
* as a rotation matrix is valid for any angle. When either X or Y
|
|
||||||
* is 0, then the scaling matrix is not invertible, which makes the
|
|
||||||
* transformation matrix not invertible as well. A 2D matrix with
|
|
||||||
* components | A B | is not invertible if and only if AD - BC = 0.
|
|
||||||
* | C D |
|
|
||||||
* This check is included above.
|
|
||||||
*/
|
|
||||||
function is_transform_invalid(transform) {
|
|
||||||
return !transform || (transform.dsdx * transform.dtdy ===
|
|
||||||
transform.dtdx * transform.dsdy); // determinant of transform
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_opaque(layer) {
|
|
||||||
if (layer.color == undefined || layer.color.a == undefined || layer.color.a != 1) return false;
|
|
||||||
return layer.isOpaque;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fills_color(layer) {
|
|
||||||
return layer.color && layer.color.a > 0 &&
|
|
||||||
layer.color.r >= 0 && layer.color.g >= 0 &&
|
|
||||||
layer.color.b >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function draws_shadows(layer) {
|
|
||||||
return layer.shadowRadius && layer.shadowRadius > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function has_blur(layer) {
|
|
||||||
return layer.backgroundBlurRadius && layer.backgroundBlurRadius > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function has_effects(layer) {
|
|
||||||
// Support previous color layer
|
|
||||||
if (layer.type === 'ColorLayer') return true;
|
|
||||||
|
|
||||||
// Support newer effect layer
|
|
||||||
return layer.type === 'EffectLayer' &&
|
|
||||||
(fills_color(layer) || draws_shadows(layer) || has_blur(layer));
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_hidden_by_policy(layer) {
|
|
||||||
return layer.flags & FLAG_HIDDEN == FLAG_HIDDEN ||
|
|
||||||
// offscreen layer root has a unique layer id
|
|
||||||
layer.id == 0x7FFFFFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the layer is visible based on its visibleRegion if available
|
|
||||||
* or its type, active buffer content, alpha and properties.
|
|
||||||
*/
|
|
||||||
function is_visible(layer, hiddenByPolicy, includesCompositionState) {
|
|
||||||
if (includesCompositionState) {
|
|
||||||
return !is_empty(layer.visibleRegion);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hiddenByPolicy) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!layer.activeBuffer && !has_effects(layer)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!layer.color || !layer.color.a || layer.color.a == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layer.occludedBy && layer.occludedBy.length > 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!layer.bounds || is_empty_rect(layer.bounds)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_visibility_reason(layer, includesCompositionState) {
|
|
||||||
if (layer.type === 'ContainerLayer') {
|
|
||||||
return 'ContainerLayer';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_hidden_by_policy(layer)) {
|
|
||||||
return 'Flag is hidden';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layer.hidden) {
|
|
||||||
return 'Hidden by parent';
|
|
||||||
}
|
|
||||||
|
|
||||||
const isBufferLayer = (layer.type === 'BufferStateLayer' ||
|
|
||||||
layer.type === 'BufferQueueLayer');
|
|
||||||
if (isBufferLayer && (!layer.activeBuffer ||
|
|
||||||
layer.activeBuffer.height === 0 || layer.activeBuffer.width === 0)) {
|
|
||||||
return 'Buffer is empty';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!layer.color || !layer.color.a || layer.color.a == 0) {
|
|
||||||
return 'Alpha is 0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_rect_empty_and_valid(layer.crop)) {
|
|
||||||
return 'Crop is 0x0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!layer.bounds || is_empty_rect(layer.bounds)) {
|
|
||||||
return 'Bounds is 0x0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_transform_invalid(layer.transform)) {
|
|
||||||
return 'Transform is invalid';
|
|
||||||
}
|
|
||||||
if (layer.isRelativeOf && layer.zOrderRelativeOf == -1) {
|
|
||||||
return 'RelativeOf layer has been removed';
|
|
||||||
}
|
|
||||||
|
|
||||||
const isEffectLayer = (layer.type === 'EffectLayer');
|
|
||||||
if (isEffectLayer && !fills_color(layer) &&
|
|
||||||
!draws_shadows(layer) && !has_blur(layer)) {
|
|
||||||
return 'Effect layer does not have color fill, shadow or blur';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layer.occludedBy && layer.occludedBy.length > 0) {
|
|
||||||
return 'Layer is occluded by:' + layer.occludedBy.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (includesCompositionState && is_empty(layer.visibleRegion)) {
|
|
||||||
return 'Visible region calculated by Composition Engine is empty';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layer.visible) {
|
|
||||||
return 'Unknown';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if rectA overlaps rectB
|
|
||||||
function overlaps(rectA, rectB) {
|
|
||||||
return rectA.left < rectB.right && rectA.right > rectB.left &&
|
|
||||||
rectA.top < rectB.bottom && rectA.bottom > rectA.top;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if outer rect contains inner rect
|
|
||||||
function contains(outerLayer, innerLayer) {
|
|
||||||
if (!is_simple_rotation(outerLayer.transform) ||
|
|
||||||
!is_simple_rotation(innerLayer.transform)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const outer = screen_bounds(outerLayer);
|
|
||||||
const inner = screen_bounds(innerLayer);
|
|
||||||
return inner.left >= outer.left && inner.top >= outer.top &&
|
|
||||||
inner.right <= outer.right && inner.bottom <= outer.bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
function screen_bounds(layer) {
|
|
||||||
if (layer.screenBounds) return layer.screenBounds;
|
|
||||||
const transformMatrix = layer.transform;
|
|
||||||
const tx = layer.position ? layer.position.x || 0 : 0;
|
|
||||||
const ty = layer.position ? layer.position.y || 0 : 0;
|
|
||||||
|
|
||||||
transformMatrix.tx = tx;
|
|
||||||
transformMatrix.ty = ty;
|
|
||||||
return multiply_rect(transformMatrix, layer.bounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Traverse in z-order from top to bottom and fill in occlusion data
|
|
||||||
function fill_occlusion_state(layerMap, rootLayers, includesCompositionState) {
|
|
||||||
const layers = rootLayers.filter((layer) => !layer.isRelativeOf);
|
|
||||||
traverse_top_to_bottom(layerMap, layers, {opaqueRects: [], transparentRects: [], screenBounds: null}, (layer, globalState) => {
|
|
||||||
if (layer.name.startsWith('Root#0') && layer.sourceBounds) {
|
|
||||||
globalState.screenBounds = {left: 0, top: 0, bottom: layer.sourceBounds.bottom, right: layer.sourceBounds.right};
|
|
||||||
}
|
|
||||||
|
|
||||||
const visible = is_visible(layer, layer.hidden, includesCompositionState);
|
|
||||||
if (visible) {
|
|
||||||
const fullyOccludes = (testLayer) => contains(testLayer, layer) && !layer.cornerRadius;
|
|
||||||
const partiallyOccludes = (testLayer) => overlaps(testLayer, layer);
|
|
||||||
const covers = (testLayer) => overlaps(testLayer, layer);
|
|
||||||
|
|
||||||
layer.occludedBy = globalState.opaqueRects.filter(fullyOccludes).map((layer) => layer.id);
|
|
||||||
layer.partiallyOccludedBy = globalState.opaqueRects.filter(partiallyOccludes)
|
|
||||||
.filter((p) => layer.occludedBy.indexOf(p.id) == -1)
|
|
||||||
.map((layer) => layer.id);
|
|
||||||
layer.coveredBy = globalState.transparentRects.filter(covers).map((layer) => layer.id);
|
|
||||||
|
|
||||||
if (is_opaque(layer)) {
|
|
||||||
globalState.opaqueRects.push(layer);
|
|
||||||
} else {
|
|
||||||
globalState.transparentRects.push(layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.visible = is_visible(layer, layer.hidden, includesCompositionState);
|
|
||||||
if (!layer.visible) {
|
|
||||||
layer.invisibleDueTo = get_visibility_reason(layer, includesCompositionState);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function traverse_top_to_bottom(layerMap, rootLayers, globalState, fn) {
|
|
||||||
for (let i = rootLayers.length-1; i >=0; i--) {
|
|
||||||
const relatives = [];
|
|
||||||
for (const id of rootLayers[i].relatives) {
|
|
||||||
if (!layerMap.hasOwnProperty(id)) {
|
|
||||||
// TODO (b/162500053): so that this doesn't need to be checked here
|
|
||||||
console.warn(
|
|
||||||
`Relative layer with id ${id} not found in dumped layers... ` +
|
|
||||||
`Skipping layer in traversal...`);
|
|
||||||
} else {
|
|
||||||
relatives.push(layerMap[id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const children = [];
|
|
||||||
for (const id of rootLayers[i].children) {
|
|
||||||
if (!layerMap.hasOwnProperty(id)) {
|
|
||||||
// TODO (b/162500053): so that this doesn't need to be checked here
|
|
||||||
console.warn(
|
|
||||||
`Child layer with id ${id} not found in dumped layers... ` +
|
|
||||||
`Skipping layer in traversal...`);
|
|
||||||
} else {
|
|
||||||
children.push(layerMap[id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// traverse through relatives and children that are not relatives
|
|
||||||
const traverseList = relatives
|
|
||||||
.concat(children.filter((layer) => !layer.isRelativeOf));
|
|
||||||
|
|
||||||
traverseList.sort((lhs, rhs) => rhs.z - lhs.z);
|
|
||||||
|
|
||||||
traverseList.filter((layer) => layer.z >=0).forEach((layer) => {
|
|
||||||
traverse_top_to_bottom(layerMap, [layer], globalState, fn);
|
|
||||||
});
|
|
||||||
|
|
||||||
fn(rootLayers[i], globalState);
|
|
||||||
|
|
||||||
traverseList.filter((layer) => layer.z < 0).forEach((layer) => {
|
|
||||||
traverse_top_to_bottom(layerMap, [layer], globalState, fn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Traverse all children and fill in any inherited states.
|
|
||||||
function fill_inherited_state(layerMap, rootLayers) {
|
|
||||||
traverse(layerMap, rootLayers, (layer, parent) => {
|
|
||||||
const parentHidden = parent && parent.hidden;
|
|
||||||
layer.hidden = is_hidden_by_policy(layer) || parentHidden;
|
|
||||||
layer.verboseFlags = flags_to_string(layer.flags);
|
|
||||||
|
|
||||||
if (!layer.bounds) {
|
|
||||||
if (!layer.sourceBounds) {
|
|
||||||
layer.bounds = layer.sourceBounds;
|
|
||||||
} else if (parent) {
|
|
||||||
layer.bounds = parent.bounds;
|
|
||||||
} else {
|
|
||||||
layer.bounds = {left: 0, top: 0, right: 0, bottom: 0};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function traverse(layerMap, rootLayers, fn) {
|
|
||||||
for (let i = rootLayers.length-1; i >=0; i--) {
|
|
||||||
const parentId = rootLayers[i].parent;
|
|
||||||
const parent = parentId == -1 ? null : layerMap[parentId];
|
|
||||||
fn(rootLayers[i], parent);
|
|
||||||
const children = rootLayers[i].children.map(
|
|
||||||
(id) => {
|
|
||||||
const child = layerMap[id];
|
|
||||||
if (child == null) {
|
|
||||||
console.warn(
|
|
||||||
`Child layer with id ${id} in parent layer id ${rootLayers[i].id} not found... ` +
|
|
||||||
`Skipping layer in traversal...`);
|
|
||||||
}
|
|
||||||
return child;
|
|
||||||
}).filter(item => item !== undefined);
|
|
||||||
traverse(layerMap, children, fn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export {fill_occlusion_state, fill_inherited_state};
|
|
||||||
@@ -14,8 +14,20 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ITreeViewElement from "./ITreeViewElement"
|
import { FILE_TYPES, TRACE_TYPES } from '@/decode.js';
|
||||||
|
import TraceBase from './TraceBase';
|
||||||
|
|
||||||
export default interface IClickableTreeViewElement extends ITreeViewElement {
|
export default class Accessibility extends TraceBase {
|
||||||
obj: any
|
accessibilityTraceFile: Object;
|
||||||
|
|
||||||
|
constructor(files) {
|
||||||
|
const accessibilityTraceFile = files[FILE_TYPES.ACCESSIBILITY_TRACE];
|
||||||
|
super(accessibilityTraceFile.data, accessibilityTraceFile.timeline, files);
|
||||||
|
|
||||||
|
this.accessibilityTraceFile = accessibilityTraceFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
get type() {
|
||||||
|
return TRACE_TYPES.ACCESSIBILITY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
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 { LayersTrace } from '@/flickerlib';
|
||||||
|
|
||||||
export default class SurfaceFlinger extends TraceBase {
|
export default class SurfaceFlinger extends TraceBase {
|
||||||
sfTraceFile: any;
|
sfTraceFile: Object;
|
||||||
|
|
||||||
constructor(files) {
|
constructor(files) {
|
||||||
const sfTraceFile = files[FILE_TYPES.SURFACE_FLINGER_TRACE];
|
const sfTraceFile = files[FILE_TYPES.SURFACE_FLINGER_TRACE];
|
||||||
@@ -30,4 +31,8 @@ export default class SurfaceFlinger extends TraceBase {
|
|||||||
get type() {
|
get type() {
|
||||||
return TRACE_TYPES.SURFACE_FLINGER;
|
return TRACE_TYPES.SURFACE_FLINGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static fromProto(proto: any): LayersTrace {
|
||||||
|
return LayersTrace.fromProto(proto);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export default class WindowManager extends TraceBase {
|
|||||||
return TRACE_TYPES.WINDOW_MANAGER;
|
return TRACE_TYPES.WINDOW_MANAGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromProto(proto): WindowManagerTrace {
|
static fromProto(proto: any): WindowManagerTrace {
|
||||||
return WindowManagerTrace.fromProto(proto);
|
return WindowManagerTrace.fromProto(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ function transform({
|
|||||||
stableId: stableIdResolved,
|
stableId: stableIdResolved,
|
||||||
visible: call(visible, obj),
|
visible: call(visible, obj),
|
||||||
childrenVisible: transformedChildren.some((c) => {
|
childrenVisible: transformedChildren.some((c) => {
|
||||||
return c.childrenVisible || c.visible;
|
return c.childrenVisible || c.isVisible;
|
||||||
}),
|
}),
|
||||||
flattened: call(flattened, obj),
|
flattened: call(flattened, obj),
|
||||||
};
|
};
|
||||||
@@ -309,7 +309,7 @@ class ObjectTransformer {
|
|||||||
|
|
||||||
transformedObj = {
|
transformedObj = {
|
||||||
kind: '',
|
kind: '',
|
||||||
name: name + ': ' + child.name,
|
name: (isTerminal(name) ? compareWithName : name) + ': ' + child.name,
|
||||||
stableId,
|
stableId,
|
||||||
children: child.children,
|
children: child.children,
|
||||||
combined: true,
|
combined: true,
|
||||||
@@ -376,6 +376,24 @@ function nanos_to_string(elapsedRealtimeNanos) {
|
|||||||
return parts.reverse().join('');
|
return parts.reverse().join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function string_to_nanos(stringTime) {
|
||||||
|
//isolate the times for each unit in an array
|
||||||
|
var times = stringTime.split(/\D+/).filter(unit => unit.length > 0);
|
||||||
|
|
||||||
|
//add zeroes to start of array if only partial timestamp is input
|
||||||
|
while (times.length<5) {
|
||||||
|
times.unshift("0");
|
||||||
|
}
|
||||||
|
|
||||||
|
var units = [24*60*60, 60*60, 60, 1, 0.001];
|
||||||
|
var nanos = 0;
|
||||||
|
//multiply the times by the relevant unit and sum
|
||||||
|
for (var x=0; x<5; x++) {
|
||||||
|
nanos += units[x]*parseInt(times[x]);
|
||||||
|
}
|
||||||
|
return nanos*(10**9);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns a UI element used highlight a visible entry.
|
// Returns a UI element used highlight a visible entry.
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
function get_visible_chip() {
|
function get_visible_chip() {
|
||||||
@@ -383,4 +401,4 @@ function get_visible_chip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
export {transform, ObjectTransformer, nanos_to_string, get_visible_chip};
|
export {transform, ObjectTransformer, nanos_to_string, string_to_nanos, get_visible_chip};
|
||||||
|
|||||||
52
tools/winscope/src/transform_accessibility.js
Normal file
52
tools/winscope/src/transform_accessibility.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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 { transform, nanos_to_string, get_visible_chip } from './transform.js'
|
||||||
|
|
||||||
|
function transform_accessibility(accessibility) {
|
||||||
|
return transform({
|
||||||
|
obj: accessibility,
|
||||||
|
kind: 'accessibility',
|
||||||
|
name: 'accessibility',
|
||||||
|
children: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function transform_entry(entry) {
|
||||||
|
return transform({
|
||||||
|
obj: entry,
|
||||||
|
kind: 'entry',
|
||||||
|
name: nanos_to_string(entry.elapsedRealtimeNanos),
|
||||||
|
children: [
|
||||||
|
[entry.accessibilityService, transform_accessibility],
|
||||||
|
],
|
||||||
|
timestamp: entry.elapsedRealtimeNanos,
|
||||||
|
stableId: 'entry'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function transform_accessibility_trace(entries) {
|
||||||
|
return transform({
|
||||||
|
obj: entries,
|
||||||
|
kind: 'entries',
|
||||||
|
name: 'entries',
|
||||||
|
children: [
|
||||||
|
[entries.entry, transform_entry],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { transform_accessibility_trace };
|
||||||
@@ -1,240 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
import {transform, nanos_to_string, get_visible_chip} from './transform.js';
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
import {fill_occlusion_state, fill_inherited_state} from './sf_visibility.js';
|
|
||||||
import {getSimplifiedLayerName} from './utils/names';
|
|
||||||
import ObjectFormatter from './flickerlib/ObjectFormatter'
|
|
||||||
|
|
||||||
const RELATIVE_Z_CHIP = {
|
|
||||||
short: 'RelZ',
|
|
||||||
long: 'Is relative Z-ordered to another surface',
|
|
||||||
class: 'warn',
|
|
||||||
};
|
|
||||||
const RELATIVE_Z_PARENT_CHIP = {
|
|
||||||
short: 'RelZParent',
|
|
||||||
long: 'Something is relative Z-ordered to this surface',
|
|
||||||
class: 'warn',
|
|
||||||
};
|
|
||||||
const MISSING_LAYER = {
|
|
||||||
short: 'MissingLayer',
|
|
||||||
long:
|
|
||||||
'This layer was referenced from the parent, but not present in the trace',
|
|
||||||
class: 'error',
|
|
||||||
};
|
|
||||||
const GPU_CHIP = {
|
|
||||||
short: 'GPU',
|
|
||||||
long: 'This layer was composed on the GPU',
|
|
||||||
class: 'gpu',
|
|
||||||
};
|
|
||||||
const HWC_CHIP = {
|
|
||||||
short: 'HWC',
|
|
||||||
long: 'This layer was composed by Hardware Composer',
|
|
||||||
class: 'hwc',
|
|
||||||
};
|
|
||||||
|
|
||||||
function transformLayer(layer) {
|
|
||||||
function offsetTo(bounds, x, y) {
|
|
||||||
return {
|
|
||||||
right: bounds.right - (bounds.left - x),
|
|
||||||
bottom: bounds.bottom - (bounds.top - y),
|
|
||||||
left: x,
|
|
||||||
top: y,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRect(layer) {
|
|
||||||
let result = layer.bounds;
|
|
||||||
const tx = layer.position ? layer.position.x || 0 : 0;
|
|
||||||
const ty = layer.position ? layer.position.y || 0 : 0;
|
|
||||||
result.label = layer.name;
|
|
||||||
result.transform = layer.transform;
|
|
||||||
result.transform.tx = tx;
|
|
||||||
result.transform.ty = ty;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addHwcCompositionTypeChip(layer) {
|
|
||||||
if (layer.hwcCompositionType === 'CLIENT') {
|
|
||||||
chips.push(GPU_CHIP);
|
|
||||||
} else if (layer.hwcCompositionType === 'DEVICE' ||
|
|
||||||
layer.hwcCompositionType === 'SOLID_COLOR') {
|
|
||||||
chips.push(HWC_CHIP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const chips = [];
|
|
||||||
if (layer.visible) {
|
|
||||||
chips.push(get_visible_chip());
|
|
||||||
}
|
|
||||||
if ((layer.zOrderRelativeOf || -1) !== -1) {
|
|
||||||
chips.push(RELATIVE_Z_CHIP);
|
|
||||||
}
|
|
||||||
if (layer.zOrderRelativeParentOf !== undefined) {
|
|
||||||
chips.push(RELATIVE_Z_PARENT_CHIP);
|
|
||||||
}
|
|
||||||
if (layer.missing) {
|
|
||||||
chips.push(MISSING_LAYER);
|
|
||||||
}
|
|
||||||
addHwcCompositionTypeChip(layer);
|
|
||||||
|
|
||||||
const rect = layer.visible && layer.bounds !== null ?
|
|
||||||
getRect(layer) : undefined;
|
|
||||||
|
|
||||||
const simplifiedLayerName = getSimplifiedLayerName(layer.name);
|
|
||||||
const shortName = simplifiedLayerName ?
|
|
||||||
layer.id + ': ' + simplifiedLayerName : undefined;
|
|
||||||
|
|
||||||
const transformedLayer = transform({
|
|
||||||
obj: ObjectFormatter.format(layer),
|
|
||||||
kind: '',
|
|
||||||
name: layer.id + ': ' + layer.name,
|
|
||||||
shortName,
|
|
||||||
children: [[layer.resolvedChildren, transformLayer]],
|
|
||||||
rect,
|
|
||||||
undefined /* bounds */,
|
|
||||||
highlight: rect,
|
|
||||||
chips,
|
|
||||||
visible: layer.visible,
|
|
||||||
freeze: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
// NOTE: Temporary until refactored to use flickerlib
|
|
||||||
transformedLayer.invisibleDueTo = layer.invisibleDueTo;
|
|
||||||
transformedLayer.occludedBy = layer.occludedBy;
|
|
||||||
transformedLayer.partiallyOccludedBy = layer.partiallyOccludedBy;
|
|
||||||
transformedLayer.coveredBy = layer.coveredBy;
|
|
||||||
|
|
||||||
return Object.freeze(transformedLayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
function missingLayer(childId) {
|
|
||||||
return {
|
|
||||||
name: 'layer #' + childId,
|
|
||||||
missing: true,
|
|
||||||
zOrderRelativeOf: -1,
|
|
||||||
transform: {dsdx: 1, dtdx: 0, dsdy: 0, dtdy: 1},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformLayers(includesCompositionState, layers) {
|
|
||||||
const idToItem = {};
|
|
||||||
const isChild = {};
|
|
||||||
|
|
||||||
const layersList = layers.layers || [];
|
|
||||||
|
|
||||||
layersList.forEach((e) => {
|
|
||||||
idToItem[e.id] = e;
|
|
||||||
});
|
|
||||||
layersList.forEach((e) => {
|
|
||||||
e.resolvedChildren = [];
|
|
||||||
if (Array.isArray(e.children)) {
|
|
||||||
e.resolvedChildren = e.children.map(
|
|
||||||
(childId) => idToItem[childId] || missingLayer(childId));
|
|
||||||
e.children.forEach((childId) => {
|
|
||||||
isChild[childId] = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// We don't clean up relatives when the relative parent is removed, so it
|
|
||||||
// may be inconsistent
|
|
||||||
if ((e.zOrderRelativeOf || -1) !== -1 && (idToItem[e.zOrderRelativeOf])) {
|
|
||||||
idToItem[e.zOrderRelativeOf].zOrderRelativeParentOf = e.id;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const roots = layersList.filter((e) => !isChild[e.id]);
|
|
||||||
fill_inherited_state(idToItem, roots);
|
|
||||||
|
|
||||||
// Backwards compatibility check
|
|
||||||
const occlusionDetectionCompatible = roots[0].bounds !== null;
|
|
||||||
if (occlusionDetectionCompatible) {
|
|
||||||
fill_occlusion_state(idToItem, roots, includesCompositionState);
|
|
||||||
}
|
|
||||||
function foreachTree(nodes, fun) {
|
|
||||||
nodes.forEach((n) => {
|
|
||||||
fun(n);
|
|
||||||
foreachTree(n.children, fun);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const idToTransformed = {};
|
|
||||||
const transformedRoots = roots.map((r) =>
|
|
||||||
transformLayer(r, {
|
|
||||||
parentBounds: {left: 0, right: 0, top: 0, bottom: 0},
|
|
||||||
parentHidden: null,
|
|
||||||
}));
|
|
||||||
|
|
||||||
foreachTree(transformedRoots, (n) => {
|
|
||||||
idToTransformed[n.obj.id] = n;
|
|
||||||
});
|
|
||||||
const flattened = [];
|
|
||||||
layersList.forEach((e) => {
|
|
||||||
flattened.push(idToTransformed[e.id]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return transform({
|
|
||||||
obj: {},
|
|
||||||
kind: 'layers',
|
|
||||||
name: 'layers',
|
|
||||||
children: [
|
|
||||||
[transformedRoots, (c) => c],
|
|
||||||
],
|
|
||||||
rectsTransform(r) {
|
|
||||||
const res = [];
|
|
||||||
flattened.forEach((l) => {
|
|
||||||
if (l.rect) {
|
|
||||||
res.push(l.rect);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res.reverse();
|
|
||||||
},
|
|
||||||
flattened,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformLayersEntry(entry) {
|
|
||||||
const includesCompositionState = !entry.excludesCompositionState;
|
|
||||||
return transform({
|
|
||||||
obj: entry,
|
|
||||||
kind: 'entry',
|
|
||||||
name: nanos_to_string(entry.elapsedRealtimeNanos) + ' - ' + entry.where,
|
|
||||||
children: [
|
|
||||||
[
|
|
||||||
[entry.layers],
|
|
||||||
(layer) => transformLayers(includesCompositionState, layer),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
timestamp: entry.elapsedRealtimeNanos,
|
|
||||||
stableId: 'entry',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformLayersTrace(entries) {
|
|
||||||
const r = transform({
|
|
||||||
obj: entries,
|
|
||||||
kind: 'layerstrace',
|
|
||||||
name: 'layerstrace',
|
|
||||||
children: [
|
|
||||||
[entries.entry, transformLayersEntry],
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {transformLayers, transformLayersTrace};
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO (b/162300507): Get rid of cloning
|
// TODO (b/162300507): Get rid of cloning
|
||||||
import cloneDeep from 'lodash.clonedeep';
|
import ObjectFormatter from '../flickerlib/ObjectFormatter';
|
||||||
|
|
||||||
export const DiffType = Object.freeze({
|
export const DiffType = Object.freeze({
|
||||||
NONE: 'none',
|
NONE: 'none',
|
||||||
@@ -26,21 +26,6 @@ export const DiffType = Object.freeze({
|
|||||||
MODIFIED: 'modified',
|
MODIFIED: 'modified',
|
||||||
});
|
});
|
||||||
|
|
||||||
export function asRawTreeViewObject(obj) {
|
|
||||||
const children = obj.children?.map(child => child.rawTreeViewObject) ?? []
|
|
||||||
|
|
||||||
return {
|
|
||||||
kind: obj.kind,
|
|
||||||
name: obj.name,
|
|
||||||
shortName: obj.shortName,
|
|
||||||
stableId: obj.stableId,
|
|
||||||
chips: obj.chips,
|
|
||||||
obj: obj.obj,
|
|
||||||
children,
|
|
||||||
ref: obj,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function defaultModifiedCheck(newNode, oldNode) {
|
export function defaultModifiedCheck(newNode, oldNode) {
|
||||||
if (!newNode && !oldNode) {
|
if (!newNode && !oldNode) {
|
||||||
return false;
|
return false;
|
||||||
@@ -50,29 +35,16 @@ export function defaultModifiedCheck(newNode, oldNode) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSON.stringify(newNode.obj) !== JSON.stringify(oldNode.obj);
|
return !newNode.equals(oldNode);
|
||||||
}
|
|
||||||
|
|
||||||
function isPrimitive(test) {
|
|
||||||
return test !== Object(test);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DiffGenerator {
|
export class DiffGenerator {
|
||||||
constructor(tree) {
|
constructor(tree) {
|
||||||
if (tree.rawTreeViewObject) {
|
|
||||||
this.tree = tree.rawTreeViewObject;
|
|
||||||
} else {
|
|
||||||
this.tree = tree;
|
this.tree = tree;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
compareWith(tree) {
|
compareWith(tree) {
|
||||||
if (tree?.rawTreeViewObject) {
|
|
||||||
this.diffWithTree = tree.rawTreeViewObject;
|
|
||||||
} else {
|
|
||||||
this.diffWithTree = tree;
|
this.diffWithTree = tree;
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,16 +112,13 @@ export class DiffGenerator {
|
|||||||
return Object.keys(obj).length === 0 && obj.constructor === Object;
|
return Object.keys(obj).length === 0 && obj.constructor === Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cloneNodeWithoutChildren(node) {
|
_cloneNode(node) {
|
||||||
const clone = {};
|
const clone = ObjectFormatter.cloneObject(node);
|
||||||
|
clone.children = node.children;
|
||||||
for (const key in node) {
|
clone.name = node.name;
|
||||||
if (key !== 'children') {
|
clone.kind = node.kind;
|
||||||
const val = node[key];
|
clone.stableId = node.stableId;
|
||||||
clone[key] = isPrimitive(val) ? val : cloneDeep(val);
|
clone.shortName = node.shortName;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +136,7 @@ export class DiffGenerator {
|
|||||||
// Deep clone newTree omitting children field
|
// Deep clone newTree omitting children field
|
||||||
// Clone is required because trees are frozen objects — we can't
|
// Clone is required because trees are frozen objects — we can't
|
||||||
// modify the original tree object. Also means there is no side effect.
|
// modify the original tree object. Also means there is no side effect.
|
||||||
const diffTree = this._cloneNodeWithoutChildren(newTree);
|
const diffTree = this._cloneNode(newTree);
|
||||||
|
|
||||||
// Default to no changes
|
// Default to no changes
|
||||||
diffTree.diff = {type: DiffType.NONE};
|
diffTree.diff = {type: DiffType.NONE};
|
||||||
@@ -200,7 +169,7 @@ export class DiffGenerator {
|
|||||||
|
|
||||||
// Check if oldTree has been deleted of moved
|
// Check if oldTree has been deleted of moved
|
||||||
if (oldTree && !newTreeSiblingIds.includes(oldId)) {
|
if (oldTree && !newTreeSiblingIds.includes(oldId)) {
|
||||||
const deletedTreeDiff = this._cloneNodeWithoutChildren(oldTree);
|
const deletedTreeDiff = this._cloneNode(oldTree);
|
||||||
|
|
||||||
if (this.newMapping[oldId]) {
|
if (this.newMapping[oldId]) {
|
||||||
deletedTreeDiff.diff = {type: DiffType.DELETED_MOVE};
|
deletedTreeDiff.diff = {type: DiffType.DELETED_MOVE};
|
||||||
@@ -233,7 +202,7 @@ export class DiffGenerator {
|
|||||||
} else if (oldTree) {
|
} else if (oldTree) {
|
||||||
if (!newTreeSiblingIds.includes(oldId)) {
|
if (!newTreeSiblingIds.includes(oldId)) {
|
||||||
// Deep clone oldTree omitting children field
|
// Deep clone oldTree omitting children field
|
||||||
const diffTree = this._cloneNodeWithoutChildren(oldTree);
|
const diffTree = this._cloneNode(oldTree);
|
||||||
|
|
||||||
// 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]) {
|
||||||
@@ -258,12 +227,12 @@ export class DiffGenerator {
|
|||||||
|
|
||||||
// TODO: Try replacing this with some sort of zipWith.
|
// TODO: Try replacing this with some sort of zipWith.
|
||||||
const numOfChildren = Math.max(
|
const numOfChildren = Math.max(
|
||||||
newTree?.children.length ?? 0, oldTree?.children.length ?? 0);
|
newTree?.children?.length ?? 0, oldTree?.children?.length ?? 0);
|
||||||
for (let i = 0; i < numOfChildren; i++) {
|
for (let i = 0; i < numOfChildren; i++) {
|
||||||
const newChild = i < newTree?.children.length ?
|
const newChild = i < newTree?.children?.length ?
|
||||||
newTree.children[i] : null;
|
newTree.children[i] : null;
|
||||||
|
|
||||||
const oldChild = i < oldTree?.children.length ?
|
const oldChild = i < oldTree?.children?.length ?
|
||||||
oldTree.children[i] : null;
|
oldTree.children[i] : null;
|
||||||
|
|
||||||
const childDiffTrees = this._generateDiffTree(
|
const childDiffTrees = this._generateDiffTree(
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
const { VueLoaderPlugin } = require("vue-loader")
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const KotlinWebpackPlugin = require('@jetbrains/kotlin-webpack-plugin');
|
const KotlinWebpackPlugin = require('@jetbrains/kotlin-webpack-plugin');
|
||||||
const HtmlWebpackInlineSourcePlugin =
|
const HtmlWebpackInlineSourcePlugin =
|
||||||
@@ -129,7 +129,7 @@ const webpackConfig = {
|
|||||||
inlineSource: isDev ? false : '.(js|css)',
|
inlineSource: isDev ? false : '.(js|css)',
|
||||||
template: 'src/index_template.html',
|
template: 'src/index_template.html',
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackInlineSourcePlugin(),
|
new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin),
|
||||||
new KotlinWebpackPlugin({
|
new KotlinWebpackPlugin({
|
||||||
src: [
|
src: [
|
||||||
path.join(__dirname, '../../../platform_testing/libraries/flicker/' +
|
path.join(__dirname, '../../../platform_testing/libraries/flicker/' +
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user