From a3a04213b7d9f2b3c8a1fc1f1c63063b057d4841 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Fri, 25 Sep 2015 13:18:29 -0700 Subject: [PATCH] Bug 1205399 - OS X: Implement disabling Notifications for the site from the native notifications. r=mstange --- .../en-US/chrome/alerts/alert.properties | 11 +++ toolkit/locales/jar.mn | 1 + widget/cocoa/OSXNotificationCenter.h | 9 +- widget/cocoa/OSXNotificationCenter.mm | 84 +++++++++++++++++-- 4 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 toolkit/locales/en-US/chrome/alerts/alert.properties diff --git a/toolkit/locales/en-US/chrome/alerts/alert.properties b/toolkit/locales/en-US/chrome/alerts/alert.properties new file mode 100644 index 00000000000..c2d8fdb6cb4 --- /dev/null +++ b/toolkit/locales/en-US/chrome/alerts/alert.properties @@ -0,0 +1,11 @@ +# 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/. + +# LOCALIZATION NOTE(closeButton.title): Used as the close button text for web notifications on OS X. +# This should ideally match the string that OS X uses for the close button on alert-type +# notifications. OS X will truncate the value if it's too long. +closeButton.title = Close +# LOCALIZATION NOTE(actionButton.label): Used as the button label to provide more actions on OS X notifications. OS X will truncate this if it's too long. +actionButton.label = … +webActions.disable.label = Disable notifications from this site diff --git a/toolkit/locales/jar.mn b/toolkit/locales/jar.mn index a8df681e447..20d517b2bbe 100644 --- a/toolkit/locales/jar.mn +++ b/toolkit/locales/jar.mn @@ -123,6 +123,7 @@ locale/@AB_CD@/pluginproblem/pluginproblem.dtd (%chrome/pluginproblem/pluginproblem.dtd) % locale alerts @AB_CD@ %locale/@AB_CD@/alerts/ locale/@AB_CD@/alerts/alert.dtd (%chrome/alerts/alert.dtd) + locale/@AB_CD@/alerts/alert.properties (%chrome/alerts/alert.properties) % locale cookie @AB_CD@ %locale/@AB_CD@/cookie/ locale/@AB_CD@/cookie/cookieAcceptDialog.dtd (%chrome/cookie/cookieAcceptDialog.dtd) locale/@AB_CD@/cookie/cookieAcceptDialog.properties (%chrome/cookie/cookieAcceptDialog.properties) diff --git a/widget/cocoa/OSXNotificationCenter.h b/widget/cocoa/OSXNotificationCenter.h index 836758cca40..48a5bf39700 100644 --- a/widget/cocoa/OSXNotificationCenter.h +++ b/widget/cocoa/OSXNotificationCenter.h @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ @@ -15,6 +15,10 @@ @class mozNotificationCenterDelegate; +#if !defined(MAC_OS_X_VERSION_10_8) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8) +typedef NSInteger NSUserNotificationActivationType; +#endif + namespace mozilla { class OSXNotificationInfo; @@ -33,7 +37,8 @@ public: nsresult Init(); void CloseAlertCocoaString(NSString *aAlertName); - void OnClick(NSString *aAlertName); + void OnActivate(NSString *aAlertName, NSUserNotificationActivationType aActivationType, + unsigned long long aAdditionalActionIndex); void ShowPendingNotification(OSXNotificationInfo *osxni); protected: diff --git a/widget/cocoa/OSXNotificationCenter.mm b/widget/cocoa/OSXNotificationCenter.mm index 145badb3b52..ff393c6b2aa 100644 --- a/widget/cocoa/OSXNotificationCenter.mm +++ b/widget/cocoa/OSXNotificationCenter.mm @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ @@ -7,9 +7,11 @@ #import #include "imgIRequest.h" #include "imgIContainer.h" +#include "nsIStringBundle.h" #include "nsNetUtil.h" #include "imgLoader.h" #import "nsCocoaUtils.h" +#include "nsContentUtils.h" #include "nsObjCExceptions.h" #include "nsString.h" #include "nsCOMPtr.h" @@ -26,9 +28,20 @@ static NSString * const NSUserNotificationDefaultSoundName = @"DefaultSoundName" enum { NSUserNotificationActivationTypeNone = 0, NSUserNotificationActivationTypeContentsClicked = 1, - NSUserNotificationActivationTypeActionButtonClicked = 2 + NSUserNotificationActivationTypeActionButtonClicked = 2, +}; +#endif + +#if !defined(MAC_OS_X_VERSION_10_9) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) +enum { + NSUserNotificationActivationTypeReplied = 3, +}; +#endif + +#if !defined(MAC_OS_X_VERSION_10_10) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10) +enum { + NSUserNotificationActivationTypeAdditionalActionClicked = 4 }; -typedef NSInteger NSUserNotificationActivationType; #endif @protocol FakeNSUserNotification @@ -90,7 +103,10 @@ typedef NSInteger NSUserNotificationActivationType; - (void)userNotificationCenter:(id)center didActivateNotification:(id)notification { - mOSXNC->OnClick([[notification userInfo] valueForKey:@"name"]); + NSNumber *alternateActionIndex = [(NSObject*)notification valueForKey:@"_alternateActionIndex"]; + mOSXNC->OnActivate([[notification userInfo] valueForKey:@"name"], + notification.activationType, + [alternateActionIndex unsignedLongLongValue]); } - (BOOL)userNotificationCenter:(id)center @@ -110,10 +126,22 @@ typedef NSInteger NSUserNotificationActivationType; } } +// This is an undocumented method that we need to be notified if a user clicks the close button. +- (void)userNotificationCenter:(id)center + didDismissAlert:(id)notification +{ + NSString *name = [[notification userInfo] valueForKey:@"name"]; + mOSXNC->CloseAlertCocoaString(name); +} + @end namespace mozilla { +enum { + OSXNotificationActionDisable = 0 +}; + class OSXNotificationInfo { private: ~OSXNotificationInfo(); @@ -217,6 +245,33 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const length:aAlertText.Length()]; notification.soundName = NSUserNotificationDefaultSoundName; notification.hasActionButton = NO; + + // If this is not an application/extension alert, show additional actions dealing with permissions. + if (!nsContentUtils::IsSystemOrExpandedPrincipal(aPrincipal) + && !aPrincipal->GetIsNullPrincipal()) { + nsCOMPtr sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID); + nsCOMPtr bundle; + nsresult rv = sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle)); + if (NS_SUCCEEDED(rv)) { + nsXPIDLString closeButtonTitle, actionButtonTitle, disableButtonTitle; + bundle->GetStringFromName(NS_LITERAL_STRING("closeButton.title").get(), + getter_Copies(closeButtonTitle)); + bundle->GetStringFromName(NS_LITERAL_STRING("actionButton.label").get(), + getter_Copies(actionButtonTitle)); + bundle->GetStringFromName(NS_LITERAL_STRING("webActions.disable.label").get(), + getter_Copies(disableButtonTitle)); + + notification.hasActionButton = YES; + notification.otherButtonTitle = nsCocoaUtils::ToNSString(closeButtonTitle); + notification.actionButtonTitle = nsCocoaUtils::ToNSString(actionButtonTitle); + [(NSObject*)notification setValue:@(YES) forKey:@"_showsButtons"]; + [(NSObject*)notification setValue:@(YES) forKey:@"_alwaysShowAlternateActionMenu"]; + [(NSObject*)notification setValue:@[ + nsCocoaUtils::ToNSString(disableButtonTitle) + ] + forKey:@"_alternateActionButtonTitles"]; + } + } NSString *alertName = [NSString stringWithCharacters:(const unichar *)aAlertName.BeginReading() length:aAlertName.Length()]; if (!alertName) { return NS_ERROR_FAILURE; @@ -318,7 +373,9 @@ OSXNotificationCenter::CloseAlertCocoaString(NSString *aAlertName) } void -OSXNotificationCenter::OnClick(NSString *aAlertName) +OSXNotificationCenter::OnActivate(NSString *aAlertName, + NSUserNotificationActivationType aActivationType, + unsigned long long aAdditionalActionIndex) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; @@ -330,7 +387,22 @@ OSXNotificationCenter::OnClick(NSString *aAlertName) OSXNotificationInfo *osxni = mActiveAlerts[i]; if ([aAlertName isEqualToString:osxni->mName]) { if (osxni->mObserver) { - osxni->mObserver->Observe(nullptr, "alertclickcallback", osxni->mCookie.get()); + switch (aActivationType) { + case NSUserNotificationActivationTypeAdditionalActionClicked: + case NSUserNotificationActivationTypeActionButtonClicked: + switch (aAdditionalActionIndex) { + case OSXNotificationActionDisable: + osxni->mObserver->Observe(nullptr, "alertdisablecallback", osxni->mCookie.get()); + break; + default: + NS_WARNING("Unknown NSUserNotification additional action clicked"); + break; + } + break; + default: + osxni->mObserver->Observe(nullptr, "alertclickcallback", osxni->mCookie.get()); + break; + } } return; }