diff --git a/tools/winscope/package.json b/tools/winscope/package.json index 2f77f411e..bf2398327 100644 --- a/tools/winscope/package.json +++ b/tools/winscope/package.json @@ -18,6 +18,7 @@ "typescript": "^4.3.5", "vue": "^2.6.14", "vue-context": "^6.0.0", + "vue-gtag": "^1.16.1", "vue-material": "^1.0.0-beta-15", "vuex": "^3.6.2" }, diff --git a/tools/winscope/src/App.vue b/tools/winscope/src/App.vue index dcb8a07ce..2621066b2 100644 --- a/tools/winscope/src/App.vue +++ b/tools/winscope/src/App.vue @@ -203,6 +203,7 @@ export default { this.store.showFileTypes = []; this.tagFile = null; this.$store.commit('clearFiles'); + this.buttonClicked("Clear") }, onDataViewFocus(file) { this.$store.commit('setActiveFile', file); @@ -252,6 +253,7 @@ export default { }, generateTags() { // generate tag file + this.buttonClicked("Generate Tags"); const engine = new TaggingEngine( this.$store.getters.tagGenerationWmTrace, this.$store.getters.tagGenerationSfTrace, diff --git a/tools/winscope/src/DataAdb.vue b/tools/winscope/src/DataAdb.vue index 0c34f2661..1cffa610b 100644 --- a/tools/winscope/src/DataAdb.vue +++ b/tools/winscope/src/DataAdb.vue @@ -31,7 +31,7 @@

Or get it from the AOSP repository.

- Download from AOSP + Download from AOSP Retry
@@ -306,8 +306,10 @@ export default { if (requested.length < 1) { this.errorText = 'No targets selected'; this.status = STATES.ERROR; + this.newEventOccurred("No targets selected"); return; } + this.newEventOccurred("Start Trace"); this.callProxy('POST', PROXY_ENDPOINTS.CONFIG_TRACE + this.deviceId() + '/', this, null, null, requestedConfig); this.status = STATES.END_TRACE; this.callProxy('POST', PROXY_ENDPOINTS.START_TRACE + this.deviceId() + '/', this, function(request, view) { @@ -315,10 +317,12 @@ export default { }, null, requested); }, dumpState() { + this.buttonClicked("Dump State"); const requested = this.toDump(); if (requested.length < 1) { this.errorText = 'No targets selected'; this.status = STATES.ERROR; + this.newEventOccurred("No targets selected"); return; } this.status = STATES.LOAD_DATA; @@ -331,6 +335,7 @@ export default { this.callProxy('POST', PROXY_ENDPOINTS.END_TRACE + this.deviceId() + '/', this, function(request, view) { view.loadFile(view.toTrace(), 0); }); + this.newEventOccurred("Ended Trace"); }, loadFile(files, idx) { this.callProxy('GET', PROXY_ENDPOINTS.FETCH + this.deviceId() + '/' + files[idx] + '/', this, function(request, view) { @@ -388,9 +393,11 @@ export default { return this.selectedDevice; }, restart() { + this.buttonClicked("Connect / Retry"); this.status = STATES.CONNECTING; }, resetLastDevice() { + this.buttonClicked("Change Device"); this.adbStore.lastDevice = ''; this.restart(); }, diff --git a/tools/winscope/src/DataInput.vue b/tools/winscope/src/DataInput.vue index 12f7ace24..c55bc990b 100644 --- a/tools/winscope/src/DataInput.vue +++ b/tools/winscope/src/DataInput.vue @@ -152,6 +152,7 @@ export default { }, hideSnackbarMessage() { this.showSnackbar = false; + this.buttonClicked("Hide Snackbar Message") }, getFetchFilesLoadingAnimation() { let frame = 0; @@ -245,10 +246,14 @@ export default { e.preventDefault(); let droppedFiles = e.dataTransfer.files; if(!droppedFiles) return; + // Record analytics event + this.draggedAndDropped(droppedFiles); + this.processFiles(droppedFiles); }, onLoadFile(e) { const files = event.target.files || event.dataTransfer.files; + this.uploadedFileThroughFilesystem(files); this.processFiles(files); }, async processFiles(files) { diff --git a/tools/winscope/src/DataView.vue b/tools/winscope/src/DataView.vue index a353e039d..52508245c 100644 --- a/tools/winscope/src/DataView.vue +++ b/tools/winscope/src/DataView.vue @@ -160,6 +160,7 @@ export default { // Pass click event to parent, so that click event handler can be attached // to component. this.$emit('click', e); + this.newEventOccurred(e.toString()); }, /** Filter data view files by current show settings */ updateShowFileTypes() { diff --git a/tools/winscope/src/Overlay.vue b/tools/winscope/src/Overlay.vue index a101cdb8e..a75f4ec3b 100644 --- a/tools/winscope/src/Overlay.vue +++ b/tools/winscope/src/Overlay.vue @@ -196,11 +196,11 @@ > expand_less - Expand timeline + Expand timeline expand_more - Collapse timeline + Collapse timeline @@ -503,6 +503,7 @@ export default { methods: { toggleSearch() { this.search = !(this.search); + this.buttonClicked("Toggle Search Bar"); }, /** * determines whether left/right arrow keys should move cursor in input field @@ -522,6 +523,7 @@ export default { const closestTimestamp = getClosestTimestamp(this.searchInput, this.mergedTimeline.timeline); this.$store.dispatch("updateTimelineTime", closestTimestamp); this.updateInputMode(false); + this.newEventOccurred("Searching for timestamp") }, emitBottomHeightUpdate() { @@ -636,12 +638,15 @@ export default { }, closeVideoOverlay() { this.showVideoOverlay = false; + this.buttonClicked("Close Video Overlay") }, openVideoOverlay() { this.showVideoOverlay = true; + this.buttonClicked("Open Video Overlay") }, toggleVideoOverlay() { this.showVideoOverlay = !this.showVideoOverlay; + this.buttonClicked("Toggle Video Overlay") }, videoLoaded() { this.$refs.videoOverlay.contentLoaded(); diff --git a/tools/winscope/src/TreeView.vue b/tools/winscope/src/TreeView.vue index 7f67fef74..e19643c5f 100644 --- a/tools/winscope/src/TreeView.vue +++ b/tools/winscope/src/TreeView.vue @@ -221,6 +221,9 @@ export default { }, toggleTree() { this.setCollapseValue(!this.isCollapsed); + if (!this.isCollapsed) { + this.openedToSeeAttributeField(this.item.name) + } }, expandTree() { this.setCollapseValue(false); diff --git a/tools/winscope/src/main.js b/tools/winscope/src/main.js index 2a983ee6a..703cced9c 100644 --- a/tools/winscope/src/main.js +++ b/tools/winscope/src/main.js @@ -17,6 +17,7 @@ import Vue from 'vue' import Vuex from 'vuex' import VueMaterial from 'vue-material' +import VueGtag from "vue-gtag"; import App from './App.vue' import { TRACE_TYPES, DUMP_TYPES, TRACE_INFO, DUMP_INFO } from './decode.js' @@ -358,6 +359,61 @@ const store = new Vuex.Store({ } }) +/** + * Make Google analytics functionalities available for recording events. + */ +Vue.use(VueGtag, { + config: { id: 'G-RRV0M08Y76'} +}) + +Vue.mixin({ + methods: { + buttonClicked(button) { + const string = "Clicked " + button + " Button"; + this.$gtag.event(string, { + 'event_category': 'Button Clicked', + 'event_label': "Winscope Interactions", + 'value': button, + }); + }, + draggedAndDropped(val) { + this.$gtag.event("Dragged And DroppedFile", { + 'event_category': 'Uploaded file', + 'event_label': "Winscope Interactions", + 'value': val, + }); + }, + uploadedFileThroughFilesystem(val) { + this.$gtag.event("Uploaded File From Filesystem", { + 'event_category': 'Uploaded file', + 'event_label': "Winscope Interactions", + 'value': val, + }); + }, + newEventOccurred(event) { + this.$gtag.event(event, { + 'event_category': event, + 'event_label': "Winscope Interactions", + 'value': 1, + }); + }, + seeingNewScreen(screenname) { + this.$gtag.screenview({ + app_name: "Winscope", + screen_name: screenname, + }) + }, + openedToSeeAttributeField(field) { + const string = "Opened field " + field; + this.$gtag.event(string, { + 'event_category': "Opened attribute field", + 'event_label': "Winscope Interactions", + 'value': field, + }); + }, + } +}); + new Vue({ el: '#app', store, // inject the Vuex store into all components diff --git a/tools/winscope/src/mixins/SaveAsZip.js b/tools/winscope/src/mixins/SaveAsZip.js index dc575394b..cf20fa40f 100644 --- a/tools/winscope/src/mixins/SaveAsZip.js +++ b/tools/winscope/src/mixins/SaveAsZip.js @@ -57,6 +57,7 @@ export default { }, async downloadAsZip(traces) { const zip = new JSZip(); + this.buttonClicked("Download All") for (const trace of traces) { const traceFolder = zip.folder(trace.type); diff --git a/tools/winscope/yarn.lock b/tools/winscope/yarn.lock index aafaf3be9..a25b41329 100644 --- a/tools/winscope/yarn.lock +++ b/tools/winscope/yarn.lock @@ -7694,6 +7694,11 @@ vue-github-buttons@^3.1.0: node-fetch "^2.3.0" tslib "^1.9.3" +vue-gtag@^1.16.1: + version "1.16.1" + resolved "https://registry.yarnpkg.com/vue-gtag/-/vue-gtag-1.16.1.tgz#edb2f20ab4f6c4d4d372dfecf8c1fcc8ab890181" + integrity sha512-5vs0pSGxdqrfXqN1Qwt0ZFXG0iTYjRMu/saddc7QIC5yp+DKgjWQRpGYVa7Pq+KbThxwzzMfo0sGi7ISa6NowA== + vue-hot-reload-api@^2.3.0: version "2.3.4" resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"