Bug 1255202 - Add UI Telemetry probes for DoorHangers. r=margaret a=ritu
authorMark Finkle <mfinkle@mozilla.com>
Fri, 18 Mar 2016 10:46:19 -0400
changeset 323772 14f023a0c143e4c215f99b5f98f0de99202ae1ee
parent 323771 a236b5c500742cf2686ae1d210e2a57ff5374269
child 323773 4265845fa3474eadf3a0372d991da3902644bd73
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmargaret, ritu
bugs1255202
milestone47.0a2
Bug 1255202 - Add UI Telemetry probes for DoorHangers. r=margaret a=ritu 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
@@ -10,16 +10,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;
 import org.mozilla.gecko.util.ColorUtils;
 
 public class ContentSecurityDoorHanger extends DoorHanger {
     private static final String LOGTAG = "GeckoSecurityDoorHanger";
 
     private final TextView mTitle;
     private final TextView mSecurityState;
@@ -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
@@ -6,16 +6,18 @@
 package org.mozilla.gecko.widget;
 
 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.mozilla.gecko.util.ColorUtils;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Context;
@@ -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.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.util.ColorUtils;
+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 = ColorUtils.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.