Bug 1255202 - Add UI Telemetry probes for DoorHangers. r=margaret
authorMark Finkle <mfinkle@mozilla.com>
Fri, 18 Mar 2016 10:46:19 -0400
changeset 289473 1fde3cca31b4e3dc322f7498f5b7a2f151d32d30
parent 289472 571fa014bb35a2026fef866abe08daa52e599a46
child 289474 d211f362a8fa08816c8f0a19fc9a2f7f11aeff43
push id30103
push userryanvm@gmail.com
push dateSat, 19 Mar 2016 15:24:26 +0000
treeherdermozilla-central@b3006e4e09af [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmargaret
bugs1255202
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1255202 - Add UI Telemetry probes for DoorHangers. r=margaret MozReview-Commit-ID: 5gsoxiMlFr1
mobile/android/base/java/org/mozilla/gecko/DoorHangerPopup.java
mobile/android/base/java/org/mozilla/gecko/TelemetryContract.java
mobile/android/base/java/org/mozilla/gecko/widget/ContentSecurityDoorHanger.java
mobile/android/base/java/org/mozilla/gecko/widget/DefaultDoorHanger.java
mobile/android/base/java/org/mozilla/gecko/widget/DoorHanger.java
mobile/android/base/java/org/mozilla/gecko/widget/LoginDoorHanger.java
mobile/android/chrome/content/WebrtcUI.js
mobile/android/docs/uitelemetry.rst
--- a/mobile/android/base/java/org/mozilla/gecko/DoorHangerPopup.java
+++ b/mobile/android/base/java/org/mozilla/gecko/DoorHangerPopup.java
@@ -115,16 +115,18 @@ public class DoorHangerPopup extends Anc
         final String typeString = json.optString("category");
         DoorHanger.Type doorhangerType = DoorHanger.Type.DEFAULT;
         if (DoorHanger.Type.LOGIN.toString().equals(typeString)) {
             doorhangerType = DoorHanger.Type.LOGIN;
         } else if (DoorHanger.Type.GEOLOCATION.toString().equals(typeString)) {
             doorhangerType = DoorHanger.Type.GEOLOCATION;
         } else if (DoorHanger.Type.DESKTOPNOTIFICATION2.toString().equals(typeString)) {
             doorhangerType = DoorHanger.Type.DESKTOPNOTIFICATION2;
+        } else if (DoorHanger.Type.WEBRTC.toString().equals(typeString)) {
+            doorhangerType = DoorHanger.Type.WEBRTC;
         }
 
         final DoorhangerConfig config = new DoorhangerConfig(tabId, id, doorhangerType, this);
 
         config.setMessage(json.getString("message"));
         config.setOptions(json.getJSONObject("options"));
 
         final JSONArray buttonArray = json.getJSONArray("buttons");
--- a/mobile/android/base/java/org/mozilla/gecko/TelemetryContract.java
+++ b/mobile/android/base/java/org/mozilla/gecko/TelemetryContract.java
@@ -143,16 +143,19 @@ public interface TelemetryContract {
         CONTENT("content"),
 
         // Action occurred via a context menu.
         CONTEXT_MENU("contextmenu"),
 
         // Action triggered from a dialog.
         DIALOG("dialog"),
 
+        // Action triggered from a doorhanger popup prompt.
+        DOORHANGER("doorhanger"),
+
         // Action triggered from a view grid item, like a thumbnail.
         GRID_ITEM("griditem"),
 
         // Action occurred via an intent.
         INTENT("intent"),
 
         // Action occurred via a homescreen launcher.
         HOMESCREEN("homescreen"),
--- a/mobile/android/base/java/org/mozilla/gecko/widget/ContentSecurityDoorHanger.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/ContentSecurityDoorHanger.java
@@ -11,16 +11,19 @@ import android.widget.Button;
 import android.widget.TextView;
 import org.mozilla.gecko.R;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Context;
 import android.view.View;
+
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.toolbar.SiteIdentityPopup;
 
 public class ContentSecurityDoorHanger extends DoorHanger {
     private static final String LOGTAG = "GeckoSecurityDoorHanger";
 
     private final TextView mTitle;
     private final TextView mSecurityState;
     private final TextView mMessage;
@@ -89,20 +92,23 @@ public class ContentSecurityDoorHanger e
                 }
                 mMessage.setVisibility(VISIBLE);
                 mSecurityState.setVisibility(VISIBLE);
             } catch (JSONException e) {}
         }
     }
 
     @Override
-    protected OnClickListener makeOnButtonClickListener(final int id) {
+    protected OnClickListener makeOnButtonClickListener(final int id, final String telemetryExtra) {
         return new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
+                final String expandedExtra = mType.toString().toLowerCase() + "-" + telemetryExtra;
+                Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.DOORHANGER, expandedExtra);
+
                 final JSONObject response = new JSONObject();
                 try {
                     switch (mType) {
                         case TRACKING:
                             response.put("allowContent", (id == SiteIdentityPopup.ButtonType.DISABLE.ordinal()));
                             response.put("contentType", ("tracking"));
                             break;
                         default:
--- a/mobile/android/base/java/org/mozilla/gecko/widget/DefaultDoorHanger.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/DefaultDoorHanger.java
@@ -7,16 +7,18 @@ package org.mozilla.gecko.widget;
 
 import android.support.v4.content.ContextCompat;
 import android.text.Html;
 import android.text.Spanned;
 import android.util.Log;
 import android.widget.Button;
 import android.widget.TextView;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.prompts.PromptInput;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Context;
 import android.text.TextUtils;
@@ -122,20 +124,23 @@ public class DefaultDoorHanger extends D
         if (!TextUtils.isEmpty(checkBoxText)) {
             mCheckBox = (CheckBox) findViewById(R.id.doorhanger_checkbox);
             mCheckBox.setText(checkBoxText);
             mCheckBox.setVisibility(VISIBLE);
         }
     }
 
     @Override
-    protected OnClickListener makeOnButtonClickListener(final int id) {
+    protected OnClickListener makeOnButtonClickListener(final int id, final String telemetryExtra) {
         return new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
+                final String expandedExtra = mType.toString().toLowerCase() + "-" + telemetryExtra;
+                Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.DOORHANGER, expandedExtra);
+
                 final JSONObject response = new JSONObject();
                 try {
                     response.put("callback", id);
 
                     CheckBox checkBox = getCheckBox();
                     // If the checkbox is being used, pass its value
                     if (checkBox != null) {
                         response.put("checked", checkBox.isChecked());
--- a/mobile/android/base/java/org/mozilla/gecko/widget/DoorHanger.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/DoorHanger.java
@@ -15,32 +15,34 @@ import android.view.View;
 import android.view.ViewStub;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import org.json.JSONObject;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
 
 public abstract class DoorHanger extends LinearLayout {
 
     public static DoorHanger Get(Context context, DoorhangerConfig config) {
         final Type type = config.getType();
         switch (type) {
             case LOGIN:
                 return new LoginDoorHanger(context, config);
             case TRACKING:
                 return new ContentSecurityDoorHanger(context, config, type);
         }
         return new DefaultDoorHanger(context, config, type);
     }
 
     // Doorhanger types created from Gecko are checked against enum strings to determine type.
-    public static enum Type { DEFAULT, LOGIN, TRACKING, GEOLOCATION, DESKTOPNOTIFICATION2 }
+    public static enum Type { DEFAULT, LOGIN, TRACKING, GEOLOCATION, DESKTOPNOTIFICATION2, WEBRTC }
 
     public interface OnButtonClickListener {
         public void onButtonClick(JSONObject response, DoorHanger doorhanger);
     }
 
     private static final String LOGTAG = "GeckoDoorHanger";
 
     // Divider between doorhangers.
@@ -92,16 +94,19 @@ public abstract class DoorHanger extends
         mPositiveButton = (Button) findViewById(R.id.doorhanger_button_positive);
         mOnButtonClickListener = config.getButtonClickListener();
 
         mDividerColor = ContextCompat.getColor(context, R.color.toolbar_divider_grey);
 
         final ViewStub contentStub = (ViewStub) findViewById(R.id.content);
         contentStub.setLayoutResource(getContentResource());
         contentStub.inflate();
+
+        final String typeExtra = mType.toString().toLowerCase();
+        Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.DOORHANGER, typeExtra);
     }
 
     protected abstract int getContentResource();
 
     protected abstract void loadConfig(DoorhangerConfig config);
 
     protected void setOptions(final JSONObject options) {
         final int persistence = options.optInt("persistence");
@@ -118,23 +123,23 @@ public abstract class DoorHanger extends
     }
 
     protected void addButtonsToLayout(DoorhangerConfig config) {
         final DoorhangerConfig.ButtonConfig negativeButtonConfig = config.getNegativeButtonConfig();
         final DoorhangerConfig.ButtonConfig positiveButtonConfig = config.getPositiveButtonConfig();
 
         if (negativeButtonConfig != null) {
             mNegativeButton.setText(negativeButtonConfig.label);
-            mNegativeButton.setOnClickListener(makeOnButtonClickListener(negativeButtonConfig.callback));
+            mNegativeButton.setOnClickListener(makeOnButtonClickListener(negativeButtonConfig.callback, "negative"));
             mNegativeButton.setVisibility(VISIBLE);
         }
 
         if (positiveButtonConfig != null) {
             mPositiveButton.setText(positiveButtonConfig.label);
-            mPositiveButton.setOnClickListener(makeOnButtonClickListener(positiveButtonConfig.callback));
+            mPositiveButton.setOnClickListener(makeOnButtonClickListener(positiveButtonConfig.callback, "positive"));
             mPositiveButton.setVisibility(VISIBLE);
         }
    }
 
     public int getTabId() {
         return mTabId;
     }
 
@@ -155,23 +160,25 @@ public abstract class DoorHanger extends
         mIcon.setVisibility(View.VISIBLE);
     }
 
     protected void addLink(String label, final String url) {
         mLink.setText(label);
         mLink.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
-                 Tabs.getInstance().loadUrlInTab(url);
+                final String typeExtra = mType.toString().toLowerCase();
+                Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.DOORHANGER, typeExtra);
+                Tabs.getInstance().loadUrlInTab(url);
             }
         });
         mLink.setVisibility(VISIBLE);
     }
 
-    protected abstract OnClickListener makeOnButtonClickListener(final int id);
+    protected abstract OnClickListener makeOnButtonClickListener(final int id, final String telemetryExtra);
 
     /*
      * Checks with persistence and timeout options to see if it's okay to remove a doorhanger.
      *
      * @param isShowing Whether or not this doorhanger is currently visible to the user.
      *                 (e.g. the DoorHanger view might be VISIBLE, but its parent could be hidden)
      */
     public boolean shouldRemove(boolean isShowing) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/LoginDoorHanger.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/LoginDoorHanger.java
@@ -23,16 +23,18 @@ import android.widget.CompoundButton;
 import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.Toast;
 import ch.boye.httpclientandroidlib.util.TextUtils;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.json.JSONArray;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 
 public class LoginDoorHanger extends DoorHanger {
     private static final String LOGTAG = "LoginDoorHanger";
     private enum ActionType { EDIT, SELECT }
 
     private final TextView mMessage;
@@ -72,20 +74,23 @@ public class LoginDoorHanger extends Doo
     protected void setOptions(final JSONObject options) {
         super.setOptions(options);
 
         final JSONObject actionText = options.optJSONObject("actionText");
         addActionText(actionText);
     }
 
     @Override
-    protected OnClickListener makeOnButtonClickListener(final int id) {
+    protected OnClickListener makeOnButtonClickListener(final int id, final String telemetryExtra) {
         return new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
+                final String expandedExtra = mType.toString().toLowerCase() + "-" + telemetryExtra;
+                Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.DOORHANGER, expandedExtra);
+
                 final JSONObject response = new JSONObject();
                 try {
                     response.put("callback", id);
                 } catch (JSONException e) {
                     Log.e(LOGTAG, "Error making doorhanger response message", e);
                 }
                 mOnButtonClickListener.onButtonClick(response, LoginDoorHanger.this);
             }
--- a/mobile/android/chrome/content/WebrtcUI.js
+++ b/mobile/android/chrome/content/WebrtcUI.js
@@ -297,11 +297,11 @@ var WebrtcUI = {
       // Only show the No Audio option if there are also Video devices to choose from
       if (videoDevices.length > 0)
         extraItems = [ Strings.browser.GetStringFromName("getUserMedia.audioDevice.none") ];
       this._addDevicesToOptions(audioDevices, "audioDevice", options, extraItems);
     }
 
     let buttons = this.getDeviceButtons(audioDevices, videoDevices, aCallID, uri);
 
-    NativeWindow.doorhanger.show(message, "webrtc-request", buttons, BrowserApp.selectedTab.id, options);
+    NativeWindow.doorhanger.show(message, "webrtc-request", buttons, BrowserApp.selectedTab.id, options, "WEBRTC");
   }
 }
--- a/mobile/android/docs/uitelemetry.rst
+++ b/mobile/android/docs/uitelemetry.rst
@@ -192,16 +192,19 @@ Methods
   Action triggered from a content page.
 
 ``contextmenu``
   Action triggered from a contextmenu. Could be from chrome or content.
 
 ``dialog``
   Action triggered from a dialog.
 
+``doorhanger``
+  Action triggered from a doorhanger popup prompt.
+
 ``griditem``
   Action triggered from a griditem, such as those used in Top Sites panel.
 
 ``homescreen``
   Action triggered from a homescreen shortcut icon.
 
 ``intent``
   Action triggered from a system Intent, usually sent from the OS.