Bug 1259148 - Notify content when a Push permissions pop-up is dismissed by the user
MozReview-Commit-ID: 7HG7oOd8RWe
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2625,16 +2625,29 @@ ContentPermissionPrompt.prototype = {
callback: function() {},
},
];
}
var options = {
learnMoreURL:
Services.urlFormatter.formatURLPref("app.support.baseURL") + "push",
+ eventCallback(type) {
+ if (type != "dismissed") {
+ return;
+ }
+ try {
+ aRequest.QueryInterface(Ci.nsIContentPermissionRequestDismissible);
+ aRequest.dismiss();
+ } catch (error) {
+ // Only the web notifications permission request can be dismissed.
+ // `PushManager.subscribe` uses the same permission, but returns a
+ // promise that can only be resolved with the final decision.
+ }
+ },
};
this._showPrompt(aRequest, message, "desktop-notification", actions,
"web-notifications",
"web-notifications-notification-icon", options);
},
_promptPointerLock: function CPP_promtPointerLock(aRequest, autoAllow) {
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -602,17 +602,19 @@ nsContentPermissionRequestProxy::Init(co
void
nsContentPermissionRequestProxy::OnParentDestroyed()
{
mRequester = nullptr;
mParent = nullptr;
}
-NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy, nsIContentPermissionRequest)
+NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy,
+ nsIContentPermissionRequest,
+ nsIContentPermissionRequestDismissible)
NS_IMETHODIMP
nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes)
{
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (mozilla::dom::nsContentPermissionUtils::ConvertPermissionRequestToArray(mPermissionRequests, types)) {
types.forget(aTypes);
return NS_OK;
@@ -737,16 +739,33 @@ nsContentPermissionRequestProxy::Allow(J
return NS_ERROR_FAILURE;
}
Unused << mParent->SendNotifyResult(true, choices);
mParent = nullptr;
return NS_OK;
}
+NS_IMETHODIMP
+nsContentPermissionRequestProxy::Dismiss()
+{
+ if (mParent == nullptr) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Don't send out the delete message when the managing protocol (PBrowser) is
+ // being destroyed and PContentPermissionRequest will soon be.
+ if (mParent->IsBeingDestroyed()) {
+ return NS_ERROR_FAILURE;
+ }
+
+ Unused << mParent->SendNotifyDismiss();
+ return NS_OK;
+}
+
void
nsContentPermissionRequestProxy::NotifyVisibility(const bool& aIsVisible)
{
MOZ_ASSERT(mRequester);
mRequester->NotifyVisibilityResult(aIsVisible);
}
@@ -832,16 +851,29 @@ RemotePermissionRequest::RecvNotifyResul
DoAllow(val);
} else {
DoCancel();
}
return true;
}
bool
+RemotePermissionRequest::RecvNotifyDismiss()
+{
+ // Don't destroy the request, since the user hasn't made a final decision.
+ NS_ASSERTION(mRequest, "We need a request");
+ nsCOMPtr<nsIContentPermissionRequestDismissible> request =
+ do_QueryInterface(mRequest);
+ if (request) {
+ request->Dismiss();
+ }
+ return true;
+}
+
+bool
RemotePermissionRequest::RecvGetVisibility()
{
nsCOMPtr<nsIDocShell> docshell = mWindow->GetDocShell();
if (!docshell) {
return false;
}
bool isActive = false;
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -114,21 +114,23 @@ private:
RefPtr<VisibilityChangeListener> mListener;
};
} // namespace dom
} // namespace mozilla
using mozilla::dom::ContentPermissionRequestParent;
-class nsContentPermissionRequestProxy : public nsIContentPermissionRequest
+class nsContentPermissionRequestProxy : public nsIContentPermissionRequest,
+ public nsIContentPermissionRequestDismissible
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
+ NS_DECL_NSICONTENTPERMISSIONREQUESTDISMISSIBLE
nsContentPermissionRequestProxy();
nsresult Init(const nsTArray<mozilla::dom::PermissionRequest>& requests,
ContentPermissionRequestParent* parent);
void OnParentDestroyed();
@@ -174,16 +176,17 @@ public:
NS_DECL_NSICONTENTPERMISSIONREQUESTCALLBACK
RemotePermissionRequest(nsIContentPermissionRequest* aRequest,
nsPIDOMWindowInner* aWindow);
// It will be called when prompt dismissed.
virtual bool RecvNotifyResult(const bool &aAllow,
InfallibleTArray<PermissionChoice>&& aChoices) override;
+ virtual bool RecvNotifyDismiss() override;
virtual bool RecvGetVisibility() override;
void IPDLAddRef()
{
mIPCOpen = true;
AddRef();
}
--- 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 : nsISupports {
+ /**
+ * 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/ipc/PContentPermissionRequest.ipdl
+++ b/dom/ipc/PContentPermissionRequest.ipdl
@@ -15,14 +15,15 @@ protocol PContentPermissionRequest
parent:
async prompt();
async NotifyVisibility(bool visibility);
async Destroy();
child:
async GetVisibility();
async NotifyResult(bool allow, PermissionChoice[] choices);
+ async NotifyDismiss();
async __delete__();
};
} // namespace dom
} // namespace mozilla
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -225,21 +225,23 @@ 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,
+ 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)
NotificationPermissionRequest(nsIPrincipal* aPrincipal,
nsPIDOMWindowInner* aWindow, Promise* aPromise,
NotificationPermissionCallback* aCallback)
: mPrincipal(aPrincipal), mWindow(aWindow),
@@ -541,16 +543,17 @@ 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(nsIContentPermissionRequestDismissible)
NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
NS_INTERFACE_MAP_ENTRY(nsIRunnable)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(NotificationPermissionRequest)
NS_IMPL_CYCLE_COLLECTING_RELEASE(NotificationPermissionRequest)
@@ -577,20 +580,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 +622,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 +657,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 +2791,8 @@ Notification::Observe(nsISupports* aSubj
}
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla
-