From 92d1bda2a2babca64d29e1cfc49d7c6031465011 Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Fri, 11 Jun 2021 16:44:23 +0800 Subject: [PATCH 01/14] Update Winscope for TaskFragment 1. Add TaskFragment.ts 2. rename ActivityTask.ts to Task.ts Bug: 190684677 Test: manual - run "yarn run dev" in winscope directory click "dumnp state" Change-Id: Ie7339af9e4906e38b73bcd01dd9fbf1d00d25a3b --- .gitignore | 2 + tools/winscope/src/flickerlib/common.js | 9 ++-- .../windows/{ActivityTask.ts => Task.ts} | 21 ++++---- .../src/flickerlib/windows/TaskFragment.ts | 52 +++++++++++++++++++ .../src/flickerlib/windows/WindowContainer.ts | 6 ++- 5 files changed, 75 insertions(+), 15 deletions(-) rename tools/winscope/src/flickerlib/windows/{ActivityTask.ts => Task.ts} (77%) create mode 100644 tools/winscope/src/flickerlib/windows/TaskFragment.ts diff --git a/.gitignore b/.gitignore index 42494a2f4..f7eb85bdb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ Thumbs.db *.iml .idea/ +*.yarn/ +.yarnrc gen/ diff --git a/tools/winscope/src/flickerlib/common.js b/tools/winscope/src/flickerlib/common.js index 7e329f18e..c439ed56d 100644 --- a/tools/winscope/src/flickerlib/common.js +++ b/tools/winscope/src/flickerlib/common.js @@ -24,8 +24,6 @@ const WindowManagerState = require('flicker').com.android.server.wm.traces.commo const Activity = require('flicker').com.android.server.wm.traces.common. windowmanager.windows.Activity; -const ActivityTask = require('flicker').com.android.server.wm.traces.common. - windowmanager.windows.ActivityTask; const Configuration = require('flicker').com.android.server.wm.traces.common. windowmanager.windows.Configuration; const ConfigurationContainer = require('flicker').com.android.server.wm.traces.common. @@ -38,6 +36,10 @@ const KeyguardControllerState = require('flicker').com.android.server.wm.traces. windowmanager.windows.KeyguardControllerState; const RootWindowContainer = require('flicker').com.android.server.wm.traces.common. windowmanager.windows.RootWindowContainer; +const Task = require('flicker').com.android.server.wm.traces.common. + windowmanager.windows.Task; +const TaskFragment = require('flicker').com.android.server.wm.traces.common. + windowmanager.windows.TaskFragment; const WindowConfiguration = require('flicker').com.android.server.wm.traces.common. windowmanager.windows.WindowConfiguration; const WindowContainer = require('flicker').com.android.server.wm.traces.common. @@ -130,13 +132,14 @@ function toTransform(proto) { export { Activity, - ActivityTask, Configuration, ConfigurationContainer, DisplayArea, DisplayContent, KeyguardControllerState, RootWindowContainer, + Task, + TaskFragment, WindowConfiguration, WindowContainer, WindowState, diff --git a/tools/winscope/src/flickerlib/windows/ActivityTask.ts b/tools/winscope/src/flickerlib/windows/Task.ts similarity index 77% rename from tools/winscope/src/flickerlib/windows/ActivityTask.ts rename to tools/winscope/src/flickerlib/windows/Task.ts index b29aa793a..7159f313e 100644 --- a/tools/winscope/src/flickerlib/windows/ActivityTask.ts +++ b/tools/winscope/src/flickerlib/windows/Task.ts @@ -16,28 +16,29 @@ import { getPropertiesForDisplay, shortenName } from '../mixin' import { asRawTreeViewObject } from '../../utils/diff.js' -import { ActivityTask, toRect } from "../common" +import { Task, toRect } from "../common" import WindowContainer from "./WindowContainer" -ActivityTask.fromProto = function (proto, isActivityInTree: Boolean): ActivityTask { +Task.fromProto = function (proto, isActivityInTree: Boolean): Task { if (proto == null) { return null } else { - const children = proto.windowContainer.children.reverse() + const windowContainerProto = proto?.taskFragment.windowContainer ?? proto.windowContainer + const children = windowContainerProto.children.reverse() .filter(it => it != null) .map(it => WindowContainer.childrenFromProto(it, isActivityInTree)) - const windowContainer = WindowContainer.fromProto({proto: proto.windowContainer, + const windowContainer = WindowContainer.fromProto({proto: windowContainerProto, children: children}) if (windowContainer == null) { throw "Window container should not be null: " + JSON.stringify(proto) } - const entry = new ActivityTask( - proto.activityType, + const entry = new Task( + proto?.taskFragment.activityType ?? proto.activityType, proto.fillsParent, toRect(proto.bounds), proto.id, proto.rootTaskId, - proto.displayId, + proto.taskFragment.displayId, toRect(proto.lastNonFullscreenBounds), proto.realActivity, proto.origActivity, @@ -47,8 +48,8 @@ ActivityTask.fromProto = function (proto, isActivityInTree: Boolean): ActivityTa proto.surfaceWidth, proto.surfaceHeight, proto.createdByOrganizer, - proto.minWidth, - proto.minHeight, + proto?.taskFragment.minWidth ?? proto.minWidth, + proto?.taskFragment.minHeight ?? proto.minHeight, windowContainer ) @@ -62,4 +63,4 @@ ActivityTask.fromProto = function (proto, isActivityInTree: Boolean): ActivityTa } } -export default ActivityTask +export default Task diff --git a/tools/winscope/src/flickerlib/windows/TaskFragment.ts b/tools/winscope/src/flickerlib/windows/TaskFragment.ts new file mode 100644 index 000000000..b3aef2b88 --- /dev/null +++ b/tools/winscope/src/flickerlib/windows/TaskFragment.ts @@ -0,0 +1,52 @@ +/* + * 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 { getPropertiesForDisplay, shortenName } from '../mixin' +import { asRawTreeViewObject } from '../../utils/diff.js' +import { TaskFragment } from "../common" +import WindowContainer from "./WindowContainer" + +TaskFragment.fromProto = function (proto, isActivityInTree: Boolean): TaskFragment { + if (proto == null) { + return null + } else { + 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}) + if (windowContainer == null) { + throw "Window container should not be null: " + JSON.stringify(proto) + } + const entry = new TaskFragment( + proto.activityType, + proto.displayId, + proto.minWidth, + proto.minHeight, + windowContainer + ) + + entry.obj = getPropertiesForDisplay(proto, entry) + entry.kind = entry.constructor.name + entry.shortName = shortenName(entry.name) + entry.rawTreeViewObject = asRawTreeViewObject(entry) + + console.warn("Created ", entry.kind, " stableId=", entry.stableId) + return entry + } +} + +export default TaskFragment diff --git a/tools/winscope/src/flickerlib/windows/WindowContainer.ts b/tools/winscope/src/flickerlib/windows/WindowContainer.ts index 756494573..154d0e23e 100644 --- a/tools/winscope/src/flickerlib/windows/WindowContainer.ts +++ b/tools/winscope/src/flickerlib/windows/WindowContainer.ts @@ -29,7 +29,8 @@ import { import Activity from "./Activity" import DisplayArea from "./DisplayArea" import DisplayContent from "./DisplayContent" -import ActivityTask from "./ActivityTask" +import Task from "./Task" +import TaskFragment from "./TaskFragment" import WindowState from "./WindowState" import WindowToken from "./WindowToken" @@ -70,7 +71,8 @@ WindowContainer.fromProto = function ({ WindowContainer.childrenFromProto = function(proto, isActivityInTree: Boolean): WindowContainerChild { return DisplayContent.fromProto(proto.displayContent, isActivityInTree) ?? DisplayArea.fromProto(proto.displayArea, isActivityInTree) ?? - ActivityTask.fromProto(proto.task, isActivityInTree) ?? + Task.fromProto(proto.task, isActivityInTree) ?? + TaskFragment.fromProto(proto.taskFragment, isActivityInTree) ?? Activity.fromProto(proto.activity) ?? WindowToken.fromProto(proto.windowToken, isActivityInTree) ?? WindowState.fromProto(proto.window, isActivityInTree) ?? From b8e901f8969d18956dab846cd14977bedad7f2ec Mon Sep 17 00:00:00 2001 From: Nataniel Borges Date: Mon, 21 Jun 2021 11:33:18 +0200 Subject: [PATCH 02/14] Backwards compat for TaskFragment + overlap fix Add backwards compatibility for traces that didn't use the TaskFragment on winscope. Moreover, fix the overlap calculation (using wrong object type) Bug: 185516271 Test: yarn run dev and open older SF and WM traces Change-Id: I8d6c98a53cf4c5062dd7a366ef467755907dc0ed (cherry picked from commit 752cec2b96716eb7c53b6326b0adcd8dbce98bf4) --- tools/winscope/src/flickerlib/windows/Task.ts | 10 +++++----- tools/winscope/src/sf_visibility.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/winscope/src/flickerlib/windows/Task.ts b/tools/winscope/src/flickerlib/windows/Task.ts index 7159f313e..76f7c0037 100644 --- a/tools/winscope/src/flickerlib/windows/Task.ts +++ b/tools/winscope/src/flickerlib/windows/Task.ts @@ -23,7 +23,7 @@ Task.fromProto = function (proto, isActivityInTree: Boolean): Task { if (proto == null) { return null } else { - const windowContainerProto = proto?.taskFragment.windowContainer ?? proto.windowContainer + const windowContainerProto = proto.taskFragment?.windowContainer ?? proto.windowContainer const children = windowContainerProto.children.reverse() .filter(it => it != null) .map(it => WindowContainer.childrenFromProto(it, isActivityInTree)) @@ -33,12 +33,12 @@ Task.fromProto = function (proto, isActivityInTree: Boolean): Task { throw "Window container should not be null: " + JSON.stringify(proto) } const entry = new Task( - proto?.taskFragment.activityType ?? proto.activityType, + proto.taskFragment?.activityType ?? proto.activityType, proto.fillsParent, toRect(proto.bounds), proto.id, proto.rootTaskId, - proto.taskFragment.displayId, + proto.taskFragment?.displayId, toRect(proto.lastNonFullscreenBounds), proto.realActivity, proto.origActivity, @@ -48,8 +48,8 @@ Task.fromProto = function (proto, isActivityInTree: Boolean): Task { proto.surfaceWidth, proto.surfaceHeight, proto.createdByOrganizer, - proto?.taskFragment.minWidth ?? proto.minWidth, - proto?.taskFragment.minHeight ?? proto.minHeight, + proto.taskFragment?.minWidth ?? proto.minWidth, + proto.taskFragment?.minHeight ?? proto.minHeight, windowContainer ) diff --git a/tools/winscope/src/sf_visibility.js b/tools/winscope/src/sf_visibility.js index 7ef8837f9..cc29f4188 100644 --- a/tools/winscope/src/sf_visibility.js +++ b/tools/winscope/src/sf_visibility.js @@ -242,8 +242,8 @@ function fill_occlusion_state(layerMap, rootLayers, includesCompositionState) { const visible = is_visible(layer, layer.hidden, includesCompositionState); if (visible) { const fullyOccludes = (testLayer) => contains(testLayer, layer) && !layer.cornerRadius; - const partiallyOccludes = (testLayer) => overlaps(screen_bounds(testLayer), screen_bounds(layer)); - const covers = (testLayer) => overlaps(screen_bounds(testLayer), screen_bounds(layer)); + 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) From f230a13f3059aab294e4a91da8e55c7296c100dd Mon Sep 17 00:00:00 2001 From: Nataniel Borges Date: Wed, 28 Jul 2021 07:13:45 +0000 Subject: [PATCH 03/14] [DO NOT MERGE] Full - Compatibilize winscope with master Bug: 194813677 Test: none Change-Id: Ie55429dcb746f597f80dfdaa68cbef19f5820005 --- tools/winscope/adb_proxy/winscope_proxy.py | 5 + tools/winscope/package.json | 84 +- tools/winscope/src/AccessibilityTraceView.vue | 35 + tools/winscope/src/App.vue | 16 +- tools/winscope/src/DataAdb.vue | 1 + tools/winscope/src/DataInput.vue | 30 +- tools/winscope/src/DataView.vue | 9 +- tools/winscope/src/LogView.vue | 41 +- tools/winscope/src/NodeContextMenu.vue | 6 +- tools/winscope/src/Overlay.vue | 48 +- tools/winscope/src/Rects.vue | 29 +- .../winscope/src/SurfaceFlingerTraceView.vue | 16 +- tools/winscope/src/TraceView.vue | 45 +- tools/winscope/src/TransactionEntry.vue | 41 +- tools/winscope/src/TransactionsView.vue | 14 +- tools/winscope/src/TreeView.vue | 6 +- tools/winscope/src/WindowManagerTraceView.vue | 4 +- tools/winscope/src/config/Configuration.json | 36 + tools/winscope/src/decode.js | 61 +- tools/winscope/src/dumps/SurfaceFlinger.ts | 9 + tools/winscope/src/dumps/WindowManager.ts | 2 +- tools/winscope/src/flickerlib/LayersTrace.ts | 35 + .../src/flickerlib/ObjectFormatter.ts | 103 +- .../src/flickerlib/WindowManagerState.ts | 81 +- .../src/flickerlib/WindowManagerTrace.ts | 23 +- tools/winscope/src/flickerlib/common.js | 265 +- tools/winscope/src/flickerlib/index.js | 5 +- tools/winscope/src/flickerlib/layers/Layer.ts | 95 + .../src/flickerlib/layers/LayerTraceEntry.ts | 66 + .../src/flickerlib/layers/Transform.ts | 90 + tools/winscope/src/flickerlib/mixin.ts | 20 +- .../winscope/src/flickerlib/treeview/Chips.ts | 32 +- .../flickerlib/treeview/ITreeViewElement.ts | 34 - .../winscope/src/flickerlib/treeview/types.ts | 12 - .../src/flickerlib/windows/Activity.ts | 43 +- .../src/flickerlib/windows/DisplayArea.ts | 40 +- .../src/flickerlib/windows/DisplayContent.ts | 55 +- tools/winscope/src/flickerlib/windows/Task.ts | 43 +- .../src/flickerlib/windows/TaskFragment.ts | 39 +- .../src/flickerlib/windows/WindowContainer.ts | 85 +- .../src/flickerlib/windows/WindowState.ts | 108 +- .../src/flickerlib/windows/WindowToken.ts | 39 +- tools/winscope/src/main.js | 3 + tools/winscope/src/matrix_utils.js | 200 +- tools/winscope/src/mixins/FileType.js | 4 + tools/winscope/src/mixins/Timeline.js | 9 +- tools/winscope/src/sf_visibility.js | 350 -- .../Accessibility.ts} | 20 +- tools/winscope/src/traces/SurfaceFlinger.ts | 7 +- tools/winscope/src/traces/WindowManager.ts | 2 +- tools/winscope/src/transform.js | 24 +- tools/winscope/src/transform_accessibility.js | 52 + tools/winscope/src/transform_sf.js | 240 -- tools/winscope/src/utils/diff.js | 65 +- tools/winscope/webpack.config.common.js | 4 +- tools/winscope/yarn.lock | 2825 ++++++++--------- 56 files changed, 2789 insertions(+), 2867 deletions(-) create mode 100644 tools/winscope/src/AccessibilityTraceView.vue create mode 100644 tools/winscope/src/config/Configuration.json create mode 100644 tools/winscope/src/flickerlib/LayersTrace.ts create mode 100644 tools/winscope/src/flickerlib/layers/Layer.ts create mode 100644 tools/winscope/src/flickerlib/layers/LayerTraceEntry.ts create mode 100644 tools/winscope/src/flickerlib/layers/Transform.ts delete mode 100644 tools/winscope/src/flickerlib/treeview/ITreeViewElement.ts delete mode 100644 tools/winscope/src/flickerlib/treeview/types.ts delete mode 100644 tools/winscope/src/sf_visibility.js rename tools/winscope/src/{flickerlib/treeview/IClickableTreeViewElement.ts => traces/Accessibility.ts} (56%) create mode 100644 tools/winscope/src/transform_accessibility.js delete mode 100644 tools/winscope/src/transform_sf.js diff --git a/tools/winscope/adb_proxy/winscope_proxy.py b/tools/winscope/adb_proxy/winscope_proxy.py index 7cf135eb4..5bfc531e2 100755 --- a/tools/winscope/adb_proxy/winscope_proxy.py +++ b/tools/winscope/adb_proxy/winscope_proxy.py @@ -115,6 +115,11 @@ TRACE_TARGETS = { 'su root cmd window tracing start\necho "WM trace started."', '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( File("/data/misc/wmtrace/layers_trace.pb", "layers_trace"), 'su root service call SurfaceFlinger 1025 i32 1\necho "SF trace started."', diff --git a/tools/winscope/package.json b/tools/winscope/package.json index 6a4633785..2f77f411e 100644 --- a/tools/winscope/package.json +++ b/tools/winscope/package.json @@ -5,60 +5,60 @@ "author": "Adrian Roos ", "private": true, "scripts": { - "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", - "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", + "dev": "cross-env NODE_ENV=development webpack serve --open --hot", + "build": "cross-env NODE_ENV=production webpack --progress", "test": "webpack --config webpack.spec.config.js && jasmine dist/bundleSpec.js" }, "dependencies": { - "cross-env": "^7.0.2", - "jszip": "^3.5.0", - "kotlin": "^1.3.72", + "cross-env": "^7.0.3", + "jszip": "^3.6.0", + "kotlin": "^1.5.21", "lodash.clonedeep": "^4.5.0", - "ts-loader": "^8.0.3", - "typescript": "^4.0.2", - "vue": "^2.3.3", - "vue-context": "^5.2.0", - "vue-material": "^1.0.0-beta-11", - "vuex": "^3.4.0" + "ts-loader": "^8.3.0", + "typescript": "^4.3.5", + "vue": "^2.6.14", + "vue-context": "^6.0.0", + "vue-material": "^1.0.0-beta-15", + "vuex": "^3.6.2" }, "devDependencies": { - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@babel/register": "^7.10.5", + "@babel/core": "^7.14.6", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.14.7", + "@babel/register": "^7.14.5", "@jetbrains/kotlin-webpack-plugin": "^3.0.2", - "@testing-library/vue": "^5.1.0", - "@types/lodash": "^4.14.158", - "babel-loader": "^8.1.0", - "compression-webpack-plugin": "^4.0.0", - "cross-env": "^7.0.2", - "css-loader": "^3.6.0", - "eslint": "^7.1.0", + "@testing-library/vue": "^5.8.1", + "@types/lodash": "^4.14.171", + "babel-loader": "^8.2.2", + "compression-webpack-plugin": "^6.1.1", + "cross-env": "^7.0.3", + "css-loader": "^5.2.7", + "eslint": "^7.30.0", "eslint-config-google": "^0.14.0", - "eslint-plugin-vue": "^6.2.2", - "file-loader": "^6.0.0", + "eslint-plugin-vue": "^7.13.0", + "file-loader": "^6.2.0", "friendly-errors-webpack-plugin": "^1.7.0", - "html-webpack-inline-source-plugin": "^0.0.10", - "html-webpack-plugin": "3.2.0", - "husky": "^4.2.5", - "jasmine": "^3.5.0", - "lint-staged": ">=10", + "html-webpack-inline-source-plugin": "^1.0.0-beta.2", + "html-webpack-plugin": "4.5.2", + "husky": "^7.0.0", + "jasmine": "^3.8.0", + "lint-staged": "^11.0.1", "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", - "protobufjs": "^6.10.0", - "source-map-loader": "^1.0.1", - "style-loader": "^1.2.1", - "ts-loader": "^8.0.1", - "typescript": "^3.9.7", + "protobufjs": "^6.11.2", + "source-map-loader": "^1.1.3", + "style-loader": "^2.0.0", + "ts-loader": "^8.3.0", + "typescript": "^4.3.5", "uglifyjs-webpack-plugin": "^2.2.0", - "vue-loader": "^15.9.3", - "vue-style-loader": "^4.1.2", - "vue-template-compiler": "^2.6.11", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0", - "webpack-merge": "^5.0.9" + "vue-loader": "^15.9.2", + "vue-style-loader": "^4.1.3", + "vue-template-compiler": "^2.6.14", + "webpack": "^4.46.0", + "webpack-cli": "^4.7.2", + "webpack-dev-server": "^3.11.2", + "webpack-merge": "^5.8.0" }, "husky": { "hooks": { diff --git a/tools/winscope/src/AccessibilityTraceView.vue b/tools/winscope/src/AccessibilityTraceView.vue new file mode 100644 index 000000000..036699e94 --- /dev/null +++ b/tools/winscope/src/AccessibilityTraceView.vue @@ -0,0 +1,35 @@ + + + + + \ No newline at end of file diff --git a/tools/winscope/src/App.vue b/tools/winscope/src/App.vue index 1b0d5ef0f..75d7b32bf 100644 --- a/tools/winscope/src/App.vue +++ b/tools/winscope/src/App.vue @@ -36,7 +36,7 @@ -
+
@@ -279,4 +279,18 @@ a { .data-view-container { 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; + } diff --git a/tools/winscope/src/DataAdb.vue b/tools/winscope/src/DataAdb.vue index c3653dacf..9b68c941c 100644 --- a/tools/winscope/src/DataAdb.vue +++ b/tools/winscope/src/DataAdb.vue @@ -200,6 +200,7 @@ const DUMPS = { const proxyFileTypeAdapter = { 'window_trace': FILE_TYPES.WINDOW_MANAGER_TRACE, + 'accessibility_trace': FILE_TYPES.ACCESSIBILITY_TRACE, 'layers_trace': FILE_TYPES.SURFACE_FLINGER_TRACE, 'wl_trace': FILE_TYPES.WAYLAND_TRACE, 'layers_dump': FILE_TYPES.SURFACE_FLINGER_DUMP, diff --git a/tools/winscope/src/DataInput.vue b/tools/winscope/src/DataInput.vue index bb07106d4..6bd7e354f 100644 --- a/tools/winscope/src/DataInput.vue +++ b/tools/winscope/src/DataInput.vue @@ -13,6 +13,7 @@ limitations under the License. --> + \ No newline at end of file diff --git a/tools/winscope/src/DataView.vue b/tools/winscope/src/DataView.vue index 0ddf12f41..db3c07f5f 100644 --- a/tools/winscope/src/DataView.vue +++ b/tools/winscope/src/DataView.vue @@ -30,7 +30,12 @@ save_alt - + \ No newline at end of file + diff --git a/tools/winscope/src/App.vue b/tools/winscope/src/App.vue index 75d7b32bf..d7717613f 100644 --- a/tools/winscope/src/App.vue +++ b/tools/winscope/src/App.vue @@ -52,13 +52,20 @@ :ref="file.type" :store="store" :file="file" + :presentTags="Object.freeze(presentTags)" + :presentErrors="Object.freeze(presentErrors)" + :dataViewFiles="dataViewFiles" @click="onDataViewFocus(file)" />
@@ -77,7 +84,8 @@ import FileType from './mixins/FileType.js'; import SaveAsZip from './mixins/SaveAsZip'; import FocusedDataViewFinder from './mixins/FocusedDataViewFinder'; import {DIRECTION} from './utils/utils'; -import {NAVIGATION_STYLE} from './utils/consts'; +import Searchbar from './Searchbar.vue'; +import {NAVIGATION_STYLE, SEARCH_TYPE} from './utils/consts'; const APP_NAME = 'Winscope'; @@ -97,11 +105,17 @@ export default { simplifyNames: true, displayDefaults: true, navigationStyle: NAVIGATION_STYLE.GLOBAL, + flickerTraceView: false, + showFileTypes: [], }), overlayRef: 'overlay', mainContentStyle: { 'padding-bottom': `${CONTENT_BOTTOM_PADDING}px`, }, + presentTags: [], + presentErrors: [], + searchTypes: [SEARCH_TYPE.TIMESTAMP], + tagAndErrorTraces: false, }; }, created() { @@ -113,8 +127,58 @@ export default { window.removeEventListener('keydown', this.onKeyDown); window.removeEventListener('scroll', this.onScroll); }, + methods: { + /** Get states from either tag files or error files */ + getUpdatedStates(files) { + var states = []; + for (const file of files) { + states.push(...file.data); + } + return states; + }, + /** Get tags from all uploaded tag files*/ + getUpdatedTags() { + var tagStates = this.getUpdatedStates(this.tagFiles); + var tags = []; + tagStates.forEach(tagState => { + tagState.tags.forEach(tag => { + tag.timestamp = tagState.timestamp; + tags.push(tag); + }); + }); + return tags; + }, + /** Get tags from all uploaded error files*/ + getUpdatedErrors() { + var errorStates = this.getUpdatedStates(this.errorFiles); + var errors = []; + //TODO (b/196201487) add check if errors empty + errorStates.forEach(errorState => { + errorState.errors.forEach(error => { + error.timestamp = errorState.timestamp; + errors.push(error); + }); + }); + return errors; + }, + /** Set flicker mode check for if there are tag/error traces uploaded*/ + shouldUpdateTagAndErrorTraces() { + return this.tagFiles.length > 0 || this.errorFiles.length > 0; + }, + /** Activate flicker search tab if tags/errors uploaded*/ + updateSearchTypes() { + this.searchTypes = [SEARCH_TYPE.TIMESTAMP]; + if (this.tagAndErrorTraces) this.searchTypes.push(SEARCH_TYPE.TAG); + }, + /** Filter data view files by current show settings*/ + updateShowFileTypes() { + this.store.showFileTypes = this.dataViewFiles + .filter((file) => file.show) + .map(file => file.type); + }, clear() { + this.store.showFileTypes = []; this.$store.commit('clearFiles'); }, onDataViewFocus(file) { @@ -139,7 +203,12 @@ export default { }, onDataReady(files) { this.$store.dispatch('setFiles', files); + this.tagAndErrorTraces = this.shouldUpdateTagAndErrorTraces(); + this.presentTags = this.getUpdatedTags(); + this.presentErrors = this.getUpdatedErrors(); + this.updateSearchTypes(); this.updateFocusedView(); + this.updateShowFileTypes(); }, setStatus(status) { if (status) { @@ -158,7 +227,10 @@ export default { }, computed: { files() { - return this.$store.getters.sortedFiles; + return this.$store.getters.sortedFiles.map(file => { + if (this.hasDataView(file)) file.show = true; + return file; + }); }, prettyDump() { return JSON.stringify(this.dump, null, 2); @@ -174,7 +246,16 @@ export default { return this.activeDataView; }, dataViewFiles() { - return this.files.filter((f) => this.hasDataView(f)); + return this.files.filter((file) => this.hasDataView(file)); + }, + tagFiles() { + return this.$store.getters.tagFiles; + }, + errorFiles() { + return this.$store.getters.errorFiles; + }, + timelineFiles() { + return this.$store.getters.timelineFiles; }, }, watch: { @@ -187,6 +268,7 @@ export default { dataview: DataView, datainput: DataInput, dataadb: DataAdb, + searchbar: Searchbar, }, }; @@ -194,7 +276,7 @@ export default { @import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@600&display=swap'); #app .md-app-container { - /* Get rid of tranforms which prevent fixed position from being used */ + /* Get rid of transforms which prevent fixed position from being used */ transform: none!important; min-height: 100vh; } @@ -240,20 +322,10 @@ export default { margin-top: 1em } -h1, -h2 { +h1 { font-weight: normal; } -ul { - list-style-type: none; - padding: 0; -} - -a { - color: #42b983; -} - .data-inputs { display: flex; flex-wrap: wrap; @@ -281,16 +353,16 @@ a { } .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; - } - + /* 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; +} + \ No newline at end of file diff --git a/tools/winscope/src/DataAdb.vue b/tools/winscope/src/DataAdb.vue index 9b68c941c..0c34f2661 100644 --- a/tools/winscope/src/DataAdb.vue +++ b/tools/winscope/src/DataAdb.vue @@ -158,6 +158,9 @@ const TRACES = { 'window_trace': { name: 'Window Manager', }, + 'accessibility_trace': { + name: 'Accessibility', + }, 'layers_trace': { name: 'Surface Flinger', }, diff --git a/tools/winscope/src/DataView.vue b/tools/winscope/src/DataView.vue index db3c07f5f..a2751f191 100644 --- a/tools/winscope/src/DataView.vue +++ b/tools/winscope/src/DataView.vue @@ -16,10 +16,15 @@
+
{{ TRACE_ICONS[file.type] }} - {{file.type}} + {{ file.type }}
-

Unrecognized DataType

+

Unrecognized DataType

@@ -150,8 +161,23 @@ export default { // to component. this.$emit('click', e); }, + /** Filter data view files by current show settings */ + updateShowFileTypes() { + this.store.showFileTypes = this.dataViewFiles + .filter((file) => file.show) + .map(file => file.type); + }, + /** Expand or collapse data view */ + toggleView() { + this.file.show = !this.file.show; + this.updateShowFileTypes(); + }, + /** Check if data view file should be shown */ + isShowFileType(type) { + return this.store.showFileTypes.find(fileType => fileType===type); + }, }, - props: ['store', 'file'], + props: ['store', 'file', 'presentTags', 'presentErrors', 'dataViewFiles'], mixins: [FileType], components: { 'traceview': TraceView, @@ -170,4 +196,18 @@ export default { font-size: 4em; color: red; } + +.toggle-view-button { + background: none; + color: inherit; + border: none; + font: inherit; + cursor: pointer; + padding-right: 10px; + display: inline-block; +} + +.md-title { + display: inline-block; +} diff --git a/tools/winscope/src/DefaultTreeElement.vue b/tools/winscope/src/DefaultTreeElement.vue index 1df8d1769..96c7dcf09 100644 --- a/tools/winscope/src/DefaultTreeElement.vue +++ b/tools/winscope/src/DefaultTreeElement.vue @@ -43,13 +43,28 @@ {{c.long}}
+
+ + {{transitionTooltip(transition)}} +
+
+ + Error: {{error.message}} +
@@ -100,4 +124,12 @@ span { flex: 1 1 auto; width: 0; } + +.flicker-tags { + display: inline-block; +} + +.error-arrow { + color: red; +} diff --git a/tools/winscope/src/NodeContextMenu.vue b/tools/winscope/src/NodeContextMenu.vue index cba46eb5c..18d86e4bd 100644 --- a/tools/winscope/src/NodeContextMenu.vue +++ b/tools/winscope/src/NodeContextMenu.vue @@ -5,7 +5,7 @@ @@ -864,4 +920,8 @@ export default { margin-bottom: 15px; cursor: help; } + +.drop-search:hover { + background-color: #9af39f; +} diff --git a/tools/winscope/src/Searchbar.vue b/tools/winscope/src/Searchbar.vue new file mode 100644 index 000000000..50aca7b55 --- /dev/null +++ b/tools/winscope/src/Searchbar.vue @@ -0,0 +1,308 @@ + + + + diff --git a/tools/winscope/src/SurfaceFlingerTraceView.vue b/tools/winscope/src/SurfaceFlingerTraceView.vue index 94234ba71..5a848c10b 100644 --- a/tools/winscope/src/SurfaceFlingerTraceView.vue +++ b/tools/winscope/src/SurfaceFlingerTraceView.vue @@ -14,15 +14,21 @@ --> +.error { + stroke: rgb(255, 0, 0); + stroke-width: 2px; +} + \ No newline at end of file diff --git a/tools/winscope/src/TraceView.vue b/tools/winscope/src/TraceView.vue index 88bcabd3d..ab77d3542 100644 --- a/tools/winscope/src/TraceView.vue +++ b/tools/winscope/src/TraceView.vue @@ -42,6 +42,7 @@ Only visible Flat + Flicker @@ -55,6 +56,10 @@ :selected="hierarchySelected" :filter="hierarchyFilter" :flattened="store.flattened" + :onlyVisible="store.onlyVisible" + :flickerTraceView="store.flickerTraceView" + :presentTags="presentTags" + :presentErrors="presentErrors" :items-clickable="true" :useGlobalCollapsedState="true" :simplify-names="store.simplifyNames" @@ -165,7 +170,7 @@ function findEntryInTree(tree, id) { export default { name: 'traceview', - props: ['store', 'file', 'summarizer'], + props: ['store', 'file', 'summarizer', 'presentTags', 'presentErrors'], data() { return { propertyFilterString: '', @@ -306,10 +311,30 @@ export default { return prevEntry; }, + + /** Performs check for id match between entry and present tags/errors + * must be carried out for every present tag/error + */ + matchItems(flickerItems, entryItem) { + var match = false; + flickerItems.forEach(flickerItem => { + if (flickerItem.taskId===entryItem.taskId || flickerItem.layerId===entryItem.id) { + match = true; + } + }); + return match; + }, + /** Returns check for id match between entry and present tags/errors */ + isEntryTagMatch(entryItem) { + return this.matchItems(this.presentTags, entryItem) || this.matchItems(this.presentErrors, entryItem); + }, }, created() { this.setData(this.file.data[this.file.selectedIndex ?? 0]); }, + destroyed() { + this.store.flickerTraceView = false; + }, watch: { selectedIndex() { this.setData(this.file.data[this.file.selectedIndex ?? 0]); @@ -337,9 +362,12 @@ export default { hierarchyFilter() { const hierarchyPropertyFilter = getFilter(this.hierarchyPropertyFilterString); - return this.store.onlyVisible ? (c) => { + var fil = this.store.onlyVisible ? (c) => { return c.isVisible && hierarchyPropertyFilter(c); } : hierarchyPropertyFilter; + return this.store.flickerTraceView ? (c) => { + return this.isEntryTagMatch(c); + } : fil; }, propertyFilter() { return getFilter(this.propertyFilterString); @@ -363,6 +391,9 @@ export default { return summary; }, + hasTagsOrErrors() { + return this.presentTags.length > 0 || this.presentErrors.length > 0; + }, }, components: { 'tree-view': TreeView, diff --git a/tools/winscope/src/TreeView.vue b/tools/winscope/src/TreeView.vue index ff574a59c..846924e6e 100644 --- a/tools/winscope/src/TreeView.vue +++ b/tools/winscope/src/TreeView.vue @@ -31,7 +31,7 @@