Bug 917480 - Part 5: UI telemetry for locale switching. r=mfinkle
authorRichard Newman <rnewman@mozilla.com>
Tue, 13 May 2014 20:50:28 -0700
changeset 183070 7cf6451e1c88
parent 183069 84cc0fb8d2f9
child 183071 2d5ab443d3c0
push id26779
push usercbook@mozilla.com
push date2014-05-14 11:02 +0000
treeherdermozilla-central@5754fc307237 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs917480
milestone32.0a1
Bug 917480 - Part 5: UI telemetry for locale switching. r=mfinkle
mobile/android/base/TelemetryContract.java
mobile/android/base/docs/index.rst
mobile/android/base/preferences/GeckoPreferences.java
--- a/mobile/android/base/TelemetryContract.java
+++ b/mobile/android/base/TelemetryContract.java
@@ -2,62 +2,70 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 /**
  * Holds data definitions for our UI Telemetry implementation.
+ *
+ * See mobile/android/base/docs/index.rst for a full dictionary.
  */
 public interface TelemetryContract {
 
     /**
      * Holds event names. Intended for use with
      * Telemetry.sendUIEvent() as the "action" parameter.
+     *
+     * Please keep this list sorted.
      */
     public interface Event {
-        // Outcome of data policy notification: can be true or false.
-        public static final String POLICY_NOTIFICATION_SUCCESS = "policynotification.success.1:";
+        // Generic action, usually for tracking menu and toolbar actions.
+        public static final String ACTION = "action.1";
 
-        // Top site pinned.
-        public static final String TOP_SITES_PIN = "pin.1";
+        // Launching (opening) an external application.
+        // Note: Only used in JavaScript for now, but here for completeness.
+        public static final String LAUNCH = "launch.1";
 
-        // Top site un-pinned.
-        public static final String TOP_SITES_UNPIN = "unpin.1";
+        // Loading a URL.
+        public static final String LOAD_URL = "loadurl.1";
 
-        // Top site edited.
-        public static final String TOP_SITES_EDIT = "edit.1";
+        public static final String LOCALE_BROWSER_RESET = "locale.browser.reset.1";
+        public static final String LOCALE_BROWSER_SELECTED = "locale.browser.selected.1";
+        public static final String LOCALE_BROWSER_UNSELECTED = "locale.browser.unselected.1";
 
         // Set default panel.
         public static final String PANEL_SET_DEFAULT = "setdefault.1";
 
-        // Sharing content.
-        public static final String SHARE = "share.1";
+        // Outcome of data policy notification: can be true or false.
+        public static final String POLICY_NOTIFICATION_SUCCESS = "policynotification.success.1:";
 
         // Sanitizing private data.
         public static final String SANITIZE = "sanitize.1";
 
         // Saving a resource (reader, bookmark, etc) for viewing later.
         // Note: Only used in JavaScript for now, but here for completeness.
         public static final String SAVE = "save.1";
 
+        // Sharing content.
+        public static final String SHARE = "share.1";
+
+        // Top site edited.
+        public static final String TOP_SITES_EDIT = "edit.1";
+
+        // Top site pinned.
+        public static final String TOP_SITES_PIN = "pin.1";
+
+        // Top site un-pinned.
+        public static final String TOP_SITES_UNPIN = "unpin.1";
+
         // Stop holding a resource (reader, bookmark, etc) for viewing later.
         // Note: Only used in JavaScript for now, but here for completeness.
         public static final String UNSAVE = "unsave.1";
-
-        // Loading a URL.
-        public static final String LOAD_URL = "loadurl.1";
-
-        // Generic action, usually for tracking menu and toolbar actions.
-        public static final String ACTION = "action.1";
-
-        // Launching (opening) an external application
-        // Note: Only used in JavaScript for now, but here for completeness.
-        public static final String LAUNCH = "launch.1";
     }
 
     /**
      * Holds event methods. Intended for use in
      * Telemetry.sendUIEvent() as the "method" parameter.
      */
     public interface Method {
         // Action triggered from a list.
--- a/mobile/android/base/docs/index.rst
+++ b/mobile/android/base/docs/index.rst
@@ -9,17 +9,17 @@ Fennec records UI events using a telemet
 
 Some links:
 
 - `Project page <https://wiki.mozilla.org/Mobile/Projects/Telemetry_probes_for_Fennec_UI_elements>`_
 - `Wiki page <https://wiki.mozilla.org/Mobile/Fennec/Android/UITelemetry>`_
 - `User research notes <https://wiki.mozilla.org/Mobile/User_Experience/Research>`_
 
 Sessions
---------
+========
 
 **Sessions** are essentially scopes. They are meant to provide context to
 events; this allows events to be simpler and more reusable. Sessions are
 usually bound to some component of the UI, some user action with a duration, or
 some transient state.
 
 For example, a session might be begun when a user begins interacting with a
 menu, and stopped when the interaction ends. Or a session might encapsulate
@@ -51,36 +51,70 @@ To stop a session, call ``Telemetry.stop
 
     ``switched``
       The user transitioned to a UI element of equal level.
 
     ``exit``
       The user left for an entirely different element.
 
 Events
-------
+======
 
 Events capture key occurrences. They should be brief and simple, and should not contain sensitive or excess information. Context for events should come from the session (scope). An event can be created with four fields (via ``Telemetry.sendUIEvent``): ``action``, ``method``, ``extras``, and ``timestamp``.
 
 ``action``
   The name of the event. Should be brief and lowercase. If needed, you can make use of namespacing with a '``.``' separator. Example event names: ``panel.switch``, ``panel.enable``, ``panel.disable``, ``panel.install``. 
 
 ``method`` (Optional)
   Used for user actions that can be performed in many ways. This field specifies the method by which the action was performed. For example, users can add an item to their reading list either by long-tapping the reader icon in the address bar, or from within reader mode. We would use the same event name for both user actions but specify two methods: ``addressbar`` and ``readermode``. 
 
 ``extras`` (Optional)
   For extra information that may be useful in understanding the event. Make an effort to keep this brief. 
 
 ``timestamp`` (Optional)
   The time at which the event occurred. If not specified, this field defaults to the current value of the realtime clock. 
 
 Versioning
-----------
+========
 
 As a we improve on our Telemetry methods, it is foreseeable that our probes will change over time. Different versions of a probe could carry different data or have different interpretations on the server-side. To make it easier for the server to handle these changes, you should add version numbers to your event and session names. An example of a versioned session is ``homepanel.1``; this is version 1 of the ``homepanel`` session. This approach should also be applied to event names, an example being: ``panel.enable.1`` and ``panel.enable.2``.
 
 
 Clock
------
+=====
 
 Times are relative to either elapsed realtime (an arbitrary monotonically increasing clock that continues to tick when the device is asleep), or elapsed uptime (which doesn't tick when the device is in deep sleep). We default to elapsed realtime.
 
 See the documentation in `the source <http://mxr.mozilla.org/mozilla-central/source/mobile/android/base/Telemetry.java>`_ for more details. 
+
+Dictionary
+==========
+
+Events
+------
+
+``policynotification.success.1:true``
+  Sent when a user has accepted the data notification policy. Can be ``false``
+  instead of ``true`` if an error occurs.
+
+``pin.1``, ``unpin.1``
+  Sent when the user pinned or unpinned a top site.
+
+``edit.1``
+  Sent when the user edits a top site.
+
+``locale.browser.reset.1``
+  When the user chooses "System default" in the browser locale picker.
+
+``locale.browser.selected.1``
+  When the user chooses a locale in the browser locale picker. The selected
+  locale is provided as the extra.
+
+``locale.browser.unselected.1``
+  When the user chose a different locale in the browser locale picker, this
+  event is fired with the previous locale as the extra. If the previous locale
+  could not be determined, "unknown" is provided.
+
+``sanitize.1``
+  Sent when the user chooses to clear private data.
+
+``setdefault.1``
+  Sent when the user makes a choice of default home panel.
--- a/mobile/android/base/preferences/GeckoPreferences.java
+++ b/mobile/android/base/preferences/GeckoPreferences.java
@@ -19,16 +19,18 @@ import org.mozilla.gecko.GeckoActivitySt
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoApplication;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.LocaleManager;
 import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.background.announcements.AnnouncementsConstants;
 import org.mozilla.gecko.background.common.GlobalConstants;
 import org.mozilla.gecko.background.healthreport.HealthReportConstants;
 import org.mozilla.gecko.home.HomePanelPicker;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.app.ActionBar;
@@ -711,33 +713,37 @@ public class GeckoPreferences
      *   A Java bridge message might not be handled.
      * * We need to adapt the preferences UI to the locale ourselves.
      * * The user might not hit Back (or Up) -- they might hit Home and never
      *   come back.
      *
      * We handle the case of the user returning to the browser via the
      * onActivityResult mechanism: see {@link BrowserApp#onActivityResult(int, int, Intent)}.
      */
-    private boolean onLocaleSelected(final String newValue) {
+    private boolean onLocaleSelected(final String currentLocale, final String newValue) {
         final Context context = getApplicationContext();
 
         // LocaleManager operations need to occur on the background thread.
         // ... but activity operations need to occur on the UI thread. So we
         // have nested runnables.
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 final LocaleManager localeManager = BrowserLocaleManager.getInstance();
 
                 if (newValue.equals("")) {
                     BrowserLocaleManager.getInstance().resetToSystemLocale(context);
+                    Telemetry.sendUIEvent(TelemetryContract.Event.LOCALE_BROWSER_RESET);
                 } else {
                     if (null == localeManager.setSelectedLocale(context, newValue)) {
                         localeManager.updateConfiguration(context, Locale.getDefault());
                     }
+                    Telemetry.sendUIEvent(TelemetryContract.Event.LOCALE_BROWSER_UNSELECTED, null,
+                                          currentLocale == null ? "unknown" : currentLocale);
+                    Telemetry.sendUIEvent(TelemetryContract.Event.LOCALE_BROWSER_SELECTED, null, newValue);
                 }
 
                 ThreadUtils.postToUiThread(new Runnable() {
                     @Override
                     public void run() {
                         onLocaleChanged(Locale.getDefault());
                     }
                 });
@@ -756,17 +762,17 @@ public class GeckoPreferences
             // We don't want the "use master password" pref to change until the
             // user has gone through the dialog.
             return false;
         }
 
         if (PREFS_BROWSER_LOCALE.equals(prefName)) {
             // Even though this is a list preference, we don't want to handle it
             // below, so we return here.
-            return onLocaleSelected((String) newValue);
+            return onLocaleSelected(BrowserLocaleManager.getLanguageTag(lastLocale), (String) newValue);
         }
 
         if (PREFS_MENU_CHAR_ENCODING.equals(prefName)) {
             setCharEncodingState(((String) newValue).equals("true"));
         } else if (PREFS_ANNOUNCEMENTS_ENABLED.equals(prefName)) {
             // Send a broadcast intent to the product announcements service, either to start or
             // to stop the repeated background checks.
             broadcastAnnouncementsPref(GeckoAppShell.getContext(), ((Boolean) newValue).booleanValue());