Bug 1259148 - Notify content when a Push permissions pop-up is dismissed by the user draft
authorPanos Astithas <past@mozilla.com>
Thu, 24 Mar 2016 19:25:23 +0200
changeset 344445 e25151961525174bde352eace74ef79ab9b4e222
parent 344444 9e4ccb1f574d3190e0ae6d69c01f30b973e1ece9
child 516951 3ff9e44f6bc7216f73e97abe8b1e85e673d33dbb
push id13821
push userbmo:past@mozilla.com
push dateThu, 24 Mar 2016 17:26:33 +0000
bugs1259148
milestone48.0a1
Bug 1259148 - Notify content when a Push permissions pop-up is dismissed by the user MozReview-Commit-ID: 7HG7oOd8RWe
browser/components/nsBrowserGlue.js
dom/interfaces/base/nsIContentPermissionPrompt.idl
dom/notification/Notification.cpp
dom/push/Push.js
toolkit/components/telemetry/Histograms.json
toolkit/components/telemetry/histogram-whitelists.json
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2594,16 +2594,17 @@ ContentPermissionPrompt.prototype = {
 
     secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST);
 
     this._showPrompt(aRequest, message, "geo", actions, "geolocation",
                      "geo-notification-icon", options);
   },
 
   _promptWebNotifications : function(aRequest) {
+    // aRequest.QueryInterface(Ci.nsIContentPermissionRequestDismissible);
     var message = gBrowserBundle.GetStringFromName("webNotifications.receiveFromSite");
 
     var actions;
 
     var browser = this._getBrowserForRequest(aRequest);
     // Only show "allow for session" in PB mode, we don't
     // support "allow for session" in non-PB mode.
     if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
@@ -2630,16 +2631,17 @@ ContentPermissionPrompt.prototype = {
           callback: function() {},
         },
       ];
     }
 
     var options = {
       learnMoreURL:
         Services.urlFormatter.formatURLPref("app.support.baseURL") + "push",
+      eventCallback: type => type == "dismissed" && aRequest.dismiss(),
     };
 
     this._showPrompt(aRequest, message, "desktop-notification", actions,
                      "web-notifications",
                      "web-notifications-notification-icon", options);
   },
 
   _promptPointerLock: function CPP_promtPointerLock(aRequest, autoAllow) {
--- a/dom/interfaces/base/nsIContentPermissionPrompt.idl
+++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl
@@ -97,16 +97,29 @@ interface nsIContentPermissionRequest : 
    * allow or cancel the request
    */
 
   void cancel();
   void allow([optional] in jsval choices); // {"type1": "choice1", "type2": "choiceA"}
 };
 
 /**
+ * Interface allows access to a content to request
+ * permission to perform a privileged operation such as
+ * push notification that can be dismissed.
+ */
+[scriptable, uuid(bc65c84f-caa6-4b8e-8a30-c83432300036)]
+interface nsIContentPermissionRequestDismissible : nsIContentPermissionRequest {
+  /**
+   * dismiss the request
+   */
+  void dismiss();
+};
+
+/**
  * Interface provides a way for the application to handle
  * the UI prompts associated with geo position.
  */
 [scriptable, function, uuid(F72DE90D-E954-4E69-9A61-917303029301)]
 interface nsIContentPermissionPrompt : nsISupports {
   /**
    * Called when a request has been made to access
    * privileged content apis
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -224,25 +224,26 @@ public:
 
     rv = notificationStorage->Get(mOrigin, mTag, mCallback);
     //XXXnsm Is it guaranteed mCallback will be called in case of failure?
     Unused << NS_WARN_IF(NS_FAILED(rv));
     return rv;
   }
 };
 
-class NotificationPermissionRequest : public nsIContentPermissionRequest,
+class NotificationPermissionRequest : public nsIContentPermissionRequestDismissible,
                                       public nsIRunnable
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUEST
+  NS_DECL_NSICONTENTPERMISSIONREQUESTDISMISSIBLE
   NS_DECL_NSIRUNNABLE
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(NotificationPermissionRequest,
-                                           nsIContentPermissionRequest)
+                                           nsIContentPermissionRequestDismissible)
 
   NotificationPermissionRequest(nsIPrincipal* aPrincipal,
                                 nsPIDOMWindowInner* aWindow, Promise* aPromise,
                                 NotificationPermissionCallback* aCallback)
     : mPrincipal(aPrincipal), mWindow(aWindow),
       mPermission(NotificationPermission::Default),
       mPromise(aPromise),
       mCallback(aCallback)
@@ -541,19 +542,19 @@ protected:
   NotificationAction mAction;
 };
 
 uint32_t Notification::sCount = 0;
 
 NS_IMPL_CYCLE_COLLECTION(NotificationPermissionRequest, mWindow, mPromise)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NotificationPermissionRequest)
-  NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
+  NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequestDismissible)
   NS_INTERFACE_MAP_ENTRY(nsIRunnable)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequestDismissible)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(NotificationPermissionRequest)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(NotificationPermissionRequest)
 
 NS_IMETHODIMP
 NotificationPermissionRequest::Run()
 {
@@ -577,20 +578,16 @@ NotificationPermissionRequest::Run()
   if (Preferences::GetBool("notification.prompt.testing", false)) {
     if (Preferences::GetBool("notification.prompt.testing.allow", true)) {
       mPermission = NotificationPermission::Granted;
     } else {
       mPermission = NotificationPermission::Denied;
     }
   }
 
-  if (mPermission != NotificationPermission::Default) {
-    return DispatchResolvePromise();
-  }
-
   return nsContentPermissionUtils::AskPermission(this, mWindow);
 }
 
 NS_IMETHODIMP
 NotificationPermissionRequest::GetPrincipal(nsIPrincipal** aRequestingPrincipal)
 {
   NS_ADDREF(*aRequestingPrincipal = mPrincipal);
   return NS_OK;
@@ -623,16 +620,23 @@ NotificationPermissionRequest::Allow(JS:
 {
   MOZ_ASSERT(aChoices.isUndefined());
 
   mPermission = NotificationPermission::Granted;
   return DispatchResolvePromise();
 }
 
 NS_IMETHODIMP
+NotificationPermissionRequest::Dismiss()
+{
+  mPermission = NotificationPermission::Default;
+  return DispatchResolvePromise();
+}
+
+NS_IMETHODIMP
 NotificationPermissionRequest::GetRequester(nsIContentPermissionRequester** aRequester)
 {
   NS_ENSURE_ARG_POINTER(aRequester);
 
   nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
   requester.forget(aRequester);
   return NS_OK;
 }
@@ -651,17 +655,21 @@ NotificationPermissionRequest::ResolvePr
   nsresult rv = NS_OK;
   if (mCallback) {
     ErrorResult error;
     mCallback->Call(mPermission, error);
     rv = error.StealNSResult();
   }
   Telemetry::Accumulate(
     Telemetry::WEB_NOTIFICATION_REQUEST_PERMISSION_CALLBACK, !!mCallback);
-  mPromise->MaybeResolve(mPermission);
+
+  if (mPermission != NotificationPermission::Default) {
+    mPromise->MaybeResolve(mPermission);
+  }
+
   return rv;
 }
 
 NS_IMETHODIMP
 NotificationPermissionRequest::GetTypes(nsIArray** aTypes)
 {
   nsTArray<nsString> emptyOptions;
   return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
@@ -2781,9 +2789,8 @@ Notification::Observe(nsISupports* aSubj
     }
   }
 
   return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
-
--- a/dom/push/Push.js
+++ b/dom/push/Push.js
@@ -146,31 +146,36 @@ Push.prototype = {
       type: "desktop-notification",
       access: null,
       options: [],
       QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType]),
     };
     let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
     typeArray.appendElement(type, false);
 
-    // create a nsIContentPermissionRequest
+    // create a nsIContentPermissionRequestDismissible
     let request = {
       types: typeArray,
       principal: this._principal,
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
+      QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequestDismissible]),
       allow: function() {
         let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_GRANTED");
         histogram.add();
         allowCallback();
       },
       cancel: function() {
         let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_DENIED");
         histogram.add();
         cancelCallback();
       },
+      dismiss: function() {
+        let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_DISMISSED");
+        histogram.add();
+        cancelCallback();
+      },
       window: this._window,
     };
 
     let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_REQUESTED");
     histogram.add(1);
     // Using askPermission from nsIDOMWindowUtils that takes care of the
     // remoting if needed.
     let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -10032,16 +10032,22 @@
     "description": "Count of number of times the PermissionManager explicitly prompted user for Push Notifications permission"
   },
   "PUSH_API_PERMISSION_DENIED": {
     "alert_emails": ["push@mozilla.com"],
     "expires_in_version": "55",
     "kind": "count",
     "description": "User explicitly denied Push Notifications permission"
   },
+  "PUSH_API_PERMISSION_DISMISSED": {
+    "alert_emails": ["push@mozilla.com"],
+    "expires_in_version": "55",
+    "kind": "count",
+    "description": "User dismissed request for Push Notifications permission"
+  },
   "PUSH_API_PERMISSION_GRANTED": {
     "alert_emails": ["push@mozilla.com"],
     "expires_in_version": "55",
     "kind": "count",
     "description": "User explicitly granted Push Notifications permission"
   },
   "PUSH_API_SUBSCRIBE_ATTEMPT": {
     "alert_emails": ["push@mozilla.com"],
--- a/toolkit/components/telemetry/histogram-whitelists.json
+++ b/toolkit/components/telemetry/histogram-whitelists.json
@@ -2163,16 +2163,17 @@
     "PREDICTOR_WAIT_TIME",
     "PROCESS_CRASH_SUBMIT_ATTEMPT",
     "PROCESS_CRASH_SUBMIT_SUCCESS",
     "PUSH_API_NOTIFICATION_RECEIVED",
     "PUSH_API_NOTIFICATION_RECEIVED_BUT_DID_NOT_NOTIFY",
     "PUSH_API_NOTIFY",
     "PUSH_API_NOTIFY_REGISTRATION_LOST",
     "PUSH_API_PERMISSION_DENIED",
+    "PUSH_API_PERMISSION_DISMISSED",
     "PUSH_API_PERMISSION_GRANTED",
     "PUSH_API_PERMISSION_REQUESTED",
     "PUSH_API_QUOTA_EXPIRATION_TIME",
     "PUSH_API_QUOTA_RESET_TO",
     "PUSH_API_SUBSCRIBE_ATTEMPT",
     "PUSH_API_SUBSCRIBE_FAILED",
     "PUSH_API_SUBSCRIBE_HTTP2_TIME",
     "PUSH_API_SUBSCRIBE_SUCCEEDED",