Merge "Report location change via CustomEvents"
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
index c7180a7..5236a1c 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
@@ -14,11 +14,24 @@
 (function() {
   'use strict';
 
-  var APP_STARTED = 'App Started';
-  var PAGE_LOADED = 'Page Loaded';
-  var TIMING_EVENT = 'timing-report';
-  var DEFAULT_CATEGORY = 'UI Latency';
-  var DEFAULT_TYPE = 'timing';
+  // Latency reporting constants.
+  var TIMING = {
+    TYPE: 'timing-report',
+    CATEGORY: 'UI Latency',
+    // Reported events - alphabetize below.
+    APP_STARTED: 'App Started',
+    PAGE_LOADED: 'Page Loaded',
+  };
+
+  // Navigation reporting constants.
+  var NAVIGATION = {
+    TYPE: 'nav-report',
+    CATEGORY: 'Location Changed',
+    PAGE: 'Page',
+  };
+
+  var CHANGE_VIEW_REGEX = /^\/c\/\d+\/?\d*$/;
+  var DIFF_VIEW_REGEX = /^\/c\/\d+\/\d+\/.+$/;
 
   Polymer({
     is: 'gr-reporting',
@@ -46,8 +59,7 @@
         name: eventName,
         value: eventValue,
       };
-      document.dispatchEvent(
-          new CustomEvent(TIMING_EVENT, {detail: detail}));
+      document.dispatchEvent(new CustomEvent(type, {detail: detail}));
       console.log(eventName + ': ' + eventValue);
     },
 
@@ -58,7 +70,7 @@
       var startTime =
           new Date().getTime() - this.performanceTiming.navigationStart;
       this.reporter(
-          DEFAULT_TYPE, DEFAULT_CATEGORY, APP_STARTED, startTime);
+          TIMING.TYPE, TIMING.CATEGORY, TIMING.APP_STARTED, startTime);
     },
 
     /**
@@ -71,10 +83,32 @@
       } else {
         var loadTime = this.performanceTiming.loadEventEnd -
             this.performanceTiming.navigationStart;
-        this.reporter(DEFAULT_TYPE, DEFAULT_CATEGORY, PAGE_LOADED, loadTime);
+        this.reporter(
+          TIMING.TYPE, TIMING.CATEGORY, TIMING.PAGE_LOADED, loadTime);
       }
     },
 
+    locationChanged: function() {
+      var page = '';
+      var pathname = this._getPathname();
+      if (pathname.startsWith('/q/')) {
+        page = '/q/';
+      } else if (pathname.match(CHANGE_VIEW_REGEX)) { // change view
+        page = '/c/';
+      } else if (pathname.match(DIFF_VIEW_REGEX)) { // diff view
+        page = '/c//COMMIT_MSG';
+      } else {
+        // Ignore other page changes.
+        return;
+      }
+      this.reporter(
+          NAVIGATION.TYPE, NAVIGATION.CATEGORY, NAVIGATION.PAGE, page);
+    },
+
+    _getPathname: function() {
+      return window.location.pathname;
+    },
+
     /**
      * Reset named timer.
      */
@@ -88,7 +122,7 @@
     timeEnd: function(name) {
       var baseTime = this._baselines[name] || 0;
       var time = this.now() - baseTime;
-      this.reporter(DEFAULT_TYPE, DEFAULT_CATEGORY, name, time);
+      this.reporter(TIMING.TYPE, TIMING.CATEGORY, name, time);
       delete this._baselines[name];
     },
   });
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
index e9226b8..b9d07fc 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
@@ -59,7 +59,7 @@
       element.appStarted();
       assert.isTrue(
           element.reporter.calledWithExactly(
-              'timing', 'UI Latency', 'App Started',
+              'timing-report', 'UI Latency', 'App Started',
               NOW_TIME - fakePerformance.navigationStart
       ));
     });
@@ -68,7 +68,7 @@
       element.pageLoaded();
       assert.isTrue(
           element.reporter.calledWithExactly(
-              'timing', 'UI Latency', 'Page Loaded',
+              'timing-report', 'UI Latency', 'Page Loaded',
               fakePerformance.loadEventEnd - fakePerformance.navigationStart)
       );
     });
@@ -83,11 +83,50 @@
       nowStub.returns(3.123);
       element.timeEnd('foo');
       assert.isTrue(element.reporter.calledWithExactly(
-          'timing', 'UI Latency', 'foo', 3.123
+          'timing-report', 'UI Latency', 'foo', 3.123
       ));
       assert.isTrue(element.reporter.calledWithExactly(
-          'timing', 'UI Latency', 'bar', 1
+          'timing-report', 'UI Latency', 'bar', 1
       ));
     });
+
+    suite('location changed', function() {
+      var pathnameStub;
+      setup(function() {
+        pathnameStub = sinon.stub(element, '_getPathname');
+      });
+
+      teardown(function() {
+        pathnameStub.restore();
+      });
+
+      test('search', function() {
+        pathnameStub.returns('/q/foo');
+        element.locationChanged();
+        assert.isTrue(element.reporter.calledWithExactly(
+            'nav-report', 'Location Changed', 'Page', '/q/'));
+      });
+
+      test('change view', function() {
+        pathnameStub.returns('/c/42/');
+        element.locationChanged();
+        assert.isTrue(element.reporter.calledWithExactly(
+            'nav-report', 'Location Changed', 'Page', '/c/'));
+      });
+
+      test('change view', function() {
+        pathnameStub.returns('/c/41/2');
+        element.locationChanged();
+        assert.isTrue(element.reporter.calledWithExactly(
+            'nav-report', 'Location Changed', 'Page', '/c/'));
+      });
+
+      test('diff view', function() {
+        pathnameStub.returns('/c/41/2/file.txt');
+        element.locationChanged();
+        assert.isTrue(element.reporter.calledWithExactly(
+            'nav-report', 'Location Changed', 'Page', '/c//COMMIT_MSG'));
+      });
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index c69e43f..ac9e03d 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -37,6 +37,7 @@
       // is processed.
       app.async(function() {
         app.fire('location-change');
+        reporting.locationChanged();
       }, 1);
       next();
     });