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"