1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sts=2 sw=2 et cin: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ToastNotification.h"
12 #include <windows.foundation.h>
13 #include <wrl/client.h>
15 #include "ErrorList.h"
16 #include "mozilla/BasePrincipal.h"
17 #include "mozilla/Buffer.h"
18 #include "mozilla/DynamicallyLinkedFunctionPtr.h"
19 #include "mozilla/mscom/COMWrappers.h"
20 #include "mozilla/Logging.h"
21 #include "mozilla/Services.h"
22 #include "mozilla/WidgetUtils.h"
23 #include "mozilla/WindowsVersion.h"
24 #include "nsAppRunner.h"
25 #include "nsComponentManagerUtils.h"
27 #include "nsIObserverService.h"
29 #include "nsThreadUtils.h"
30 #include "nsWindowsHelpers.h"
31 #include "nsXREDirProvider.h"
33 #include "ToastNotificationHandler.h"
34 #include "WinTaskbar.h"
40 using namespace ABI::Windows::Foundation
;
41 using namespace Microsoft::WRL
;
42 using namespace Microsoft::WRL::Wrappers
;
43 // Needed to disambiguate internal and Windows `ToastNotification` classes.
44 using namespace ABI::Windows::UI::Notifications
;
45 using WinToastNotification
= ABI::Windows::UI::Notifications::ToastNotification
;
46 using IVectorView_ToastNotification
=
47 ABI::Windows::Foundation::Collections::IVectorView
<WinToastNotification
*>;
48 using IVectorView_ScheduledToastNotification
=
49 ABI::Windows::Foundation::Collections::IVectorView
<
50 ScheduledToastNotification
*>;
52 LazyLogModule
sWASLog("WindowsAlertsService");
54 NS_IMPL_ISUPPORTS(ToastNotification
, nsIAlertsService
, nsIWindowsAlertsService
,
55 nsIAlertsDoNotDisturb
, nsIObserver
)
57 ToastNotification::ToastNotification() = default;
59 ToastNotification::~ToastNotification() = default;
61 nsresult
ToastNotification::Init() {
62 if (!IsWin8OrLater()) {
63 return NS_ERROR_NOT_IMPLEMENTED
;
66 if (!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
67 // Windows Toast Notification requires AppId. But allow `xpcshell` to
68 // create the service to test other functionality.
69 if (!EnsureAumidRegistered()) {
70 MOZ_LOG(sWASLog
, LogLevel::Warning
, ("Failed to register AUMID!"));
71 return NS_ERROR_NOT_IMPLEMENTED
;
74 MOZ_LOG(sWASLog
, LogLevel::Info
, ("Using dummy AUMID in xpcshell test"));
75 mAumid
.emplace(u
"XpcshellTestToastAumid"_ns
);
78 MOZ_LOG(sWASLog
, LogLevel::Info
,
79 ("Using AUMID: '%s'", NS_ConvertUTF16toUTF8(mAumid
.ref()).get()));
81 nsCOMPtr
<nsIObserverService
> obsServ
=
82 mozilla::services::GetObserverService();
85 NS_FAILED(obsServ
->AddObserver(this, "last-pb-context-exited", false)));
87 NS_FAILED(obsServ
->AddObserver(this, "quit-application", false)));
93 bool ToastNotification::EnsureAumidRegistered() {
94 // Check if this is an MSIX install, app identity is provided by the package
95 // so no registration is necessary.
96 if (AssignIfMsixAumid(mAumid
)) {
98 sWASLog
, LogLevel::Info
,
99 ("Found MSIX AUMID: '%s'", NS_ConvertUTF16toUTF8(mAumid
.ref()).get()));
103 nsAutoString installHash
;
104 nsresult rv
= gDirServiceProvider
->GetInstallHash(installHash
);
105 NS_ENSURE_SUCCESS(rv
, false);
107 // Check if toasts were registered during NSIS/MSI installation.
108 if (AssignIfNsisAumid(installHash
, mAumid
)) {
109 MOZ_LOG(sWASLog
, LogLevel::Info
,
110 ("Found AUMID from installer (with install hash '%s'): '%s'",
111 NS_ConvertUTF16toUTF8(installHash
).get(),
112 NS_ConvertUTF16toUTF8(mAumid
.ref()).get()));
116 // No AUMID registered, fall through to runtime registration for development
117 // and portable builds.
118 if (RegisterRuntimeAumid(installHash
, mAumid
)) {
120 sWASLog
, LogLevel::Info
,
121 ("Updated AUMID registration at runtime (for install hash '%s'): '%s'",
122 NS_ConvertUTF16toUTF8(installHash
).get(),
123 NS_ConvertUTF16toUTF8(mAumid
.ref()).get()));
127 MOZ_LOG(sWASLog
, LogLevel::Warning
,
128 ("Failed to register AUMID at runtime! (for install hash '%s')",
129 NS_ConvertUTF16toUTF8(installHash
).get()));
133 bool ToastNotification::AssignIfMsixAumid(Maybe
<nsAutoString
>& aAumid
) {
134 // `GetCurrentApplicationUserModelId` added in Windows 8.
135 DynamicallyLinkedFunctionPtr
<decltype(&GetCurrentApplicationUserModelId
)>
136 pGetCurrentApplicationUserModelId(L
"kernel32.dll",
137 "GetCurrentApplicationUserModelId");
138 if (!pGetCurrentApplicationUserModelId
) {
143 // ERROR_INSUFFICIENT_BUFFER signals that we're in an MSIX package, and
144 // therefore should use the package's AUMID.
145 if (pGetCurrentApplicationUserModelId(&len
, nullptr) !=
146 ERROR_INSUFFICIENT_BUFFER
) {
147 MOZ_LOG(sWASLog
, LogLevel::Debug
, ("Not an MSIX package"));
150 mozilla::Buffer
<wchar_t> buffer(len
);
151 LONG success
= pGetCurrentApplicationUserModelId(&len
, buffer
.Elements());
152 NS_ENSURE_TRUE(success
== ERROR_SUCCESS
, false);
154 aAumid
.emplace(buffer
.Elements());
158 bool ToastNotification::AssignIfNsisAumid(nsAutoString
& aInstallHash
,
159 Maybe
<nsAutoString
>& aAumid
) {
160 nsAutoString nsisAumidName
=
161 u
""_ns MOZ_TOAST_APP_NAME u
"Toast-"_ns
+ aInstallHash
;
162 nsAutoString nsisAumidPath
= u
"AppUserModelId\\"_ns
+ nsisAumidName
;
163 if (!WinUtils::HasRegistryKey(HKEY_CLASSES_ROOT
, nsisAumidPath
.get())) {
164 MOZ_LOG(sWASLog
, LogLevel::Debug
,
165 ("No CustomActivator value from installer in key 'HKCR\\%s'",
166 NS_ConvertUTF16toUTF8(nsisAumidPath
).get()));
170 aAumid
.emplace(nsisAumidName
);
174 bool ToastNotification::RegisterRuntimeAumid(nsAutoString
& aInstallHash
,
175 Maybe
<nsAutoString
>& aAumid
) {
176 // Portable AUMID slightly differs from installed AUMID so we can
177 // differentiate installed to HKCU vs portable installs if necessary.
178 nsAutoString portableAumid
=
179 u
""_ns MOZ_TOAST_APP_NAME u
"PortableToast-"_ns
+ aInstallHash
;
181 nsCOMPtr
<nsIFile
> appdir
;
182 nsresult rv
= gDirServiceProvider
->GetGREDir()->Clone(getter_AddRefs(appdir
));
183 NS_ENSURE_SUCCESS(rv
, false);
185 nsCOMPtr
<nsIFile
> icon
;
186 rv
= appdir
->Clone(getter_AddRefs(icon
));
187 NS_ENSURE_SUCCESS(rv
, false);
189 rv
= icon
->Append(u
"browser"_ns
);
190 NS_ENSURE_SUCCESS(rv
, false);
192 rv
= icon
->Append(u
"VisualElements"_ns
);
193 NS_ENSURE_SUCCESS(rv
, false);
195 rv
= icon
->Append(u
"VisualElements_70.png"_ns
);
196 NS_ENSURE_SUCCESS(rv
, false);
198 nsAutoString iconPath
;
199 rv
= icon
->GetPath(iconPath
);
200 NS_ENSURE_SUCCESS(rv
, false);
202 nsCOMPtr
<nsIFile
> comDll
;
203 rv
= appdir
->Clone(getter_AddRefs(comDll
));
204 NS_ENSURE_SUCCESS(rv
, false);
206 rv
= comDll
->Append(u
"notificationserver.dll"_ns
);
207 NS_ENSURE_SUCCESS(rv
, false);
209 nsAutoString dllPath
;
210 rv
= comDll
->GetPath(dllPath
);
211 NS_ENSURE_SUCCESS(rv
, false);
214 // Manipulate the registry using a transaction so that any failures are
216 wchar_t transactionName
[] = L
"" MOZ_TOAST_APP_NAME L
" toast registration";
217 txn
.own(::CreateTransaction(nullptr, nullptr, TRANSACTION_DO_NOT_PROMOTE
, 0,
218 0, 0, transactionName
));
219 NS_ENSURE_TRUE(txn
.get() != INVALID_HANDLE_VALUE
, false);
223 auto RegisterKey
= [&](const nsAString
& path
, nsAutoRegKey
& key
) {
225 status
= ::RegCreateKeyTransactedW(
226 HKEY_CURRENT_USER
, PromiseFlatString(path
).get(), 0, nullptr,
227 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, nullptr, &rawKey
, nullptr, txn
,
229 NS_ENSURE_TRUE(status
== ERROR_SUCCESS
, false);
234 auto RegisterValue
= [&](nsAutoRegKey
& key
, const nsAString
& name
,
235 unsigned long type
, const nsAString
& data
) {
236 status
= ::RegSetValueExW(
237 key
, PromiseFlatString(name
).get(), 0, type
,
238 static_cast<const BYTE
*>(PromiseFlatString(data
).get()),
239 (data
.Length() + 1) * sizeof(wchar_t));
241 return status
== ERROR_SUCCESS
;
245 /* Writes the following keys and values to the registry.
246 * HKEY_CURRENT_USER\Software\Classes\AppID\{GUID} DllSurrogate : REG_SZ = ""
247 * \AppUserModelId\{MOZ_TOAST_APP_NAME}PortableToast-{install hash} CustomActivator : REG_SZ = {GUID}
248 * DisplayName : REG_EXPAND_SZ = {display name}
249 * IconUri : REG_EXPAND_SZ = {icon path}
250 * \CLSID\{GUID} AppID : REG_SZ = {GUID}
251 * \InprocServer32 (Default) : REG_SZ = {notificationserver.dll path}
255 constexpr nsLiteralString classes
= u
"Software\\Classes\\"_ns
;
257 nsAutoString aumid
= classes
+ u
"AppUserModelId\\"_ns
+ portableAumid
;
258 nsAutoRegKey aumidKey
;
259 NS_ENSURE_TRUE(RegisterKey(aumid
, aumidKey
), false);
261 nsAutoString guidStr
;
263 DWORD bufferSizeBytes
= NSID_LENGTH
* sizeof(wchar_t);
264 Buffer
<wchar_t> guidBuffer(bufferSizeBytes
);
265 status
= ::RegGetValueW(HKEY_CURRENT_USER
, aumid
.get(), L
"CustomActivator",
266 RRF_RT_REG_SZ
, 0, guidBuffer
.Elements(),
270 if (status
== ERROR_SUCCESS
&&
271 SUCCEEDED(CLSIDFromString(guidBuffer
.Elements(), &unused
))) {
272 guidStr
= guidBuffer
.Elements();
274 nsIDToCString
uuidString(nsID::GenerateUUID());
275 size_t len
= strlen(uuidString
.get());
276 MOZ_ASSERT(len
== NSID_LENGTH
- 1);
277 CopyASCIItoUTF16(nsDependentCSubstring(uuidString
.get(), len
), guidStr
);
280 if (status
== ERROR_SUCCESS
) {
281 MOZ_LOG(sWASLog
, LogLevel::Debug
,
282 ("Existing CustomActivator guid found: '%s'",
283 NS_ConvertUTF16toUTF8(guidStr
).get()));
285 MOZ_LOG(sWASLog
, LogLevel::Debug
,
286 ("New CustomActivator guid generated: '%s'",
287 NS_ConvertUTF16toUTF8(guidStr
).get()));
291 RegisterValue(aumidKey
, u
"CustomActivator"_ns
, REG_SZ
, guidStr
), false);
292 nsAutoString brandName
;
293 WidgetUtils::GetBrandShortName(brandName
);
295 RegisterValue(aumidKey
, u
"DisplayName"_ns
, REG_EXPAND_SZ
, brandName
),
298 RegisterValue(aumidKey
, u
"IconUri"_ns
, REG_EXPAND_SZ
, iconPath
), false);
300 nsAutoString appid
= classes
+ u
"AppID\\"_ns
+ guidStr
;
301 nsAutoRegKey appidKey
;
302 NS_ENSURE_TRUE(RegisterKey(appid
, appidKey
), false);
303 NS_ENSURE_TRUE(RegisterValue(appidKey
, u
"DllSurrogate"_ns
, REG_SZ
, u
""_ns
),
306 nsAutoString clsid
= classes
+ u
"CLSID\\"_ns
+ guidStr
;
307 nsAutoRegKey clsidKey
;
308 NS_ENSURE_TRUE(RegisterKey(clsid
, clsidKey
), false);
309 NS_ENSURE_TRUE(RegisterValue(clsidKey
, u
"AppID"_ns
, REG_SZ
, guidStr
), false);
311 nsAutoString inproc
= clsid
+ u
"\\InprocServer32"_ns
;
312 nsAutoRegKey inprocKey
;
313 NS_ENSURE_TRUE(RegisterKey(inproc
, inprocKey
), false);
314 // Set the component's path to this DLL
315 NS_ENSURE_TRUE(RegisterValue(inprocKey
, u
""_ns
, REG_SZ
, dllPath
), false);
317 NS_ENSURE_TRUE(::CommitTransaction(txn
), false);
320 sWASLog
, LogLevel::Debug
,
321 ("Updated registration for CustomActivator value in key 'HKCU\\%s': '%s'",
322 NS_ConvertUTF16toUTF8(aumid
).get(),
323 NS_ConvertUTF16toUTF8(guidStr
).get()));
324 aAumid
.emplace(portableAumid
);
328 nsresult
ToastNotification::BackgroundDispatch(nsIRunnable
* runnable
) {
329 return NS_DispatchBackgroundTask(runnable
);
333 ToastNotification::GetSuppressForScreenSharing(bool* aRetVal
) {
334 *aRetVal
= mSuppressForScreenSharing
;
339 ToastNotification::SetSuppressForScreenSharing(bool aSuppress
) {
340 mSuppressForScreenSharing
= aSuppress
;
345 ToastNotification::Observe(nsISupports
* aSubject
, const char* aTopic
,
346 const char16_t
* aData
) {
347 nsDependentCString
topic(aTopic
);
349 for (auto iter
= mActiveHandlers
.Iter(); !iter
.Done(); iter
.Next()) {
350 RefPtr
<ToastNotificationHandler
> handler
= iter
.UserData();
351 if (topic
== "last-pb-context-exited"_ns
) {
352 handler
->HideIfPrivate();
353 } else if (topic
== "quit-application"_ns
) {
354 // The handlers' destructors will do the right thing (de-register with
358 // Break the cycle between the handler and the MSCOM notification so the
359 // handler's destructor will be called.
360 handler
->UnregisterHandler();
368 ToastNotification::ShowAlertNotification(
369 const nsAString
& aImageUrl
, const nsAString
& aAlertTitle
,
370 const nsAString
& aAlertText
, bool aAlertTextClickable
,
371 const nsAString
& aAlertCookie
, nsIObserver
* aAlertListener
,
372 const nsAString
& aAlertName
, const nsAString
& aBidi
, const nsAString
& aLang
,
373 const nsAString
& aData
, nsIPrincipal
* aPrincipal
, bool aInPrivateBrowsing
,
374 bool aRequireInteraction
) {
375 nsCOMPtr
<nsIAlertNotification
> alert
=
376 do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID
);
377 if (NS_WARN_IF(!alert
)) {
378 return NS_ERROR_FAILURE
;
380 // vibrate is unused for now
381 nsTArray
<uint32_t> vibrate
;
382 nsresult rv
= alert
->Init(aAlertName
, aImageUrl
, aAlertTitle
, aAlertText
,
383 aAlertTextClickable
, aAlertCookie
, aBidi
, aLang
,
384 aData
, aPrincipal
, aInPrivateBrowsing
,
385 aRequireInteraction
, false, vibrate
);
386 if (NS_WARN_IF(NS_FAILED(rv
))) {
389 return ShowAlert(alert
, aAlertListener
);
393 ToastNotification::ShowPersistentNotification(const nsAString
& aPersistentData
,
394 nsIAlertNotification
* aAlert
,
395 nsIObserver
* aAlertListener
) {
396 return ShowAlert(aAlert
, aAlertListener
);
400 ToastNotification::SetManualDoNotDisturb(bool aDoNotDisturb
) {
401 return NS_ERROR_NOT_IMPLEMENTED
;
405 ToastNotification::GetManualDoNotDisturb(bool* aRet
) {
406 return NS_ERROR_NOT_IMPLEMENTED
;
410 ToastNotification::ShowAlert(nsIAlertNotification
* aAlert
,
411 nsIObserver
* aAlertListener
) {
412 NS_ENSURE_ARG(aAlert
);
414 if (mSuppressForScreenSharing
) {
419 MOZ_TRY(aAlert
->GetCookie(cookie
));
422 MOZ_TRY(aAlert
->GetName(name
));
425 MOZ_TRY(aAlert
->GetTitle(title
));
428 MOZ_TRY(aAlert
->GetText(text
));
431 MOZ_TRY(aAlert
->GetTextClickable(&textClickable
));
433 nsAutoString hostPort
;
434 MOZ_TRY(aAlert
->GetSource(hostPort
));
436 nsAutoString launchUrl
;
437 MOZ_TRY(aAlert
->GetLaunchURL(launchUrl
));
439 bool requireInteraction
;
440 MOZ_TRY(aAlert
->GetRequireInteraction(&requireInteraction
));
442 bool inPrivateBrowsing
;
443 MOZ_TRY(aAlert
->GetInPrivateBrowsing(&inPrivateBrowsing
));
445 nsTArray
<RefPtr
<nsIAlertAction
>> actions
;
446 MOZ_TRY(aAlert
->GetActions(actions
));
448 nsCOMPtr
<nsIPrincipal
> principal
;
449 MOZ_TRY(aAlert
->GetPrincipal(getter_AddRefs(principal
)));
450 bool isSystemPrincipal
= principal
&& principal
->IsSystemPrincipal();
452 RefPtr
<ToastNotificationHandler
> oldHandler
= mActiveHandlers
.Get(name
);
454 NS_ENSURE_TRUE(mAumid
.isSome(), NS_ERROR_UNEXPECTED
);
455 RefPtr
<ToastNotificationHandler
> handler
= new ToastNotificationHandler(
456 this, mAumid
.ref(), aAlertListener
, name
, cookie
, title
, text
, hostPort
,
457 textClickable
, requireInteraction
, actions
, isSystemPrincipal
, launchUrl
,
459 mActiveHandlers
.InsertOrUpdate(name
, RefPtr
{handler
});
461 MOZ_LOG(sWASLog
, LogLevel::Debug
,
462 ("Adding handler '%s': [%p] (now %d handlers)",
463 NS_ConvertUTF16toUTF8(name
).get(), handler
.get(),
464 mActiveHandlers
.Count()));
466 nsresult rv
= handler
->InitAlertAsync(aAlert
);
467 if (NS_WARN_IF(NS_FAILED(rv
))) {
468 MOZ_LOG(sWASLog
, LogLevel::Debug
,
469 ("Failed to init alert, removing '%s'",
470 NS_ConvertUTF16toUTF8(name
).get()));
471 mActiveHandlers
.Remove(name
);
472 handler
->UnregisterHandler();
476 // If there was a previous handler with the same name then unregister it.
478 oldHandler
->UnregisterHandler();
485 ToastNotification::GetXmlStringForWindowsAlert(nsIAlertNotification
* aAlert
,
486 const nsAString
& aWindowsTag
,
487 nsAString
& aString
) {
488 NS_ENSURE_ARG(aAlert
);
491 MOZ_TRY(aAlert
->GetCookie(cookie
));
494 MOZ_TRY(aAlert
->GetName(name
));
497 MOZ_TRY(aAlert
->GetTitle(title
));
500 MOZ_TRY(aAlert
->GetText(text
));
503 MOZ_TRY(aAlert
->GetTextClickable(&textClickable
));
505 nsAutoString hostPort
;
506 MOZ_TRY(aAlert
->GetSource(hostPort
));
508 nsAutoString launchUrl
;
509 MOZ_TRY(aAlert
->GetLaunchURL(launchUrl
));
511 bool requireInteraction
;
512 MOZ_TRY(aAlert
->GetRequireInteraction(&requireInteraction
));
514 bool inPrivateBrowsing
;
515 MOZ_TRY(aAlert
->GetInPrivateBrowsing(&inPrivateBrowsing
));
517 nsTArray
<RefPtr
<nsIAlertAction
>> actions
;
518 MOZ_TRY(aAlert
->GetActions(actions
));
520 nsCOMPtr
<nsIPrincipal
> principal
;
521 MOZ_TRY(aAlert
->GetPrincipal(getter_AddRefs(principal
)));
522 bool isSystemPrincipal
= principal
&& principal
->IsSystemPrincipal();
524 NS_ENSURE_TRUE(mAumid
.isSome(), NS_ERROR_UNEXPECTED
);
525 RefPtr
<ToastNotificationHandler
> handler
= new ToastNotificationHandler(
526 this, mAumid
.ref(), nullptr /* aAlertListener */, name
, cookie
, title
,
527 text
, hostPort
, textClickable
, requireInteraction
, actions
,
528 isSystemPrincipal
, launchUrl
, inPrivateBrowsing
);
530 // Usually, this will be empty during testing, making test output
532 MOZ_TRY(handler
->SetWindowsTag(aWindowsTag
));
534 nsAutoString imageURL
;
535 MOZ_TRY(aAlert
->GetImageURL(imageURL
));
537 return handler
->CreateToastXmlString(imageURL
, aString
);
541 ToastNotification::HandleWindowsTag(const nsAString
& aWindowsTag
,
542 nsIUnknownWindowsTagListener
* aListener
,
545 NS_ENSURE_TRUE(mAumid
.isSome(), NS_ERROR_UNEXPECTED
);
547 MOZ_LOG(sWASLog
, LogLevel::Debug
,
548 ("Iterating %d handlers", mActiveHandlers
.Count()));
550 for (auto iter
= mActiveHandlers
.Iter(); !iter
.Done(); iter
.Next()) {
551 RefPtr
<ToastNotificationHandler
> handler
= iter
.UserData();
553 nsresult rv
= handler
->GetWindowsTag(tag
);
555 if (NS_SUCCEEDED(rv
)) {
556 MOZ_LOG(sWASLog
, LogLevel::Debug
,
557 ("Comparing external windowsTag '%s' to handled windowsTag '%s'",
558 NS_ConvertUTF16toUTF8(aWindowsTag
).get(),
559 NS_ConvertUTF16toUTF8(tag
).get()));
560 if (aWindowsTag
.Equals(tag
)) {
561 MOZ_LOG(sWASLog
, LogLevel::Debug
,
562 ("External windowsTag '%s' is handled by handler [%p]",
563 NS_ConvertUTF16toUTF8(aWindowsTag
).get(), handler
.get()));
566 nsString
eventName(aWindowsTag
);
568 OpenEventW(EVENT_MODIFY_STATE
, FALSE
, eventName
.get()));
570 if (SetEvent(event
)) {
571 MOZ_LOG(sWASLog
, LogLevel::Info
,
572 ("Set event for event named '%s'",
573 NS_ConvertUTF16toUTF8(eventName
).get()));
576 sWASLog
, LogLevel::Error
,
577 ("Failed to set event for event named '%s' (GetLastError=%lu)",
578 NS_ConvertUTF16toUTF8(eventName
).get(), GetLastError()));
581 MOZ_LOG(sWASLog
, LogLevel::Error
,
582 ("Failed to open event named '%s' (GetLastError=%lu)",
583 NS_ConvertUTF16toUTF8(eventName
).get(), GetLastError()));
589 MOZ_LOG(sWASLog
, LogLevel::Debug
,
590 ("Failed to get windowsTag for handler [%p]", handler
.get()));
594 MOZ_LOG(sWASLog
, LogLevel::Debug
, ("aListener [%p]", aListener
));
597 nsAutoString launchUrl
;
598 nsAutoString privilegedName
;
600 ToastNotificationHandler::FindLaunchURLAndPrivilegedNameForWindowsTag(
601 aWindowsTag
, mAumid
.ref(), foundTag
, launchUrl
, privilegedName
));
603 // The tag should always be found, so invoke the callback (even just for
605 aListener
->HandleUnknownWindowsTag(aWindowsTag
, launchUrl
, privilegedName
);
612 ToastNotification::CloseAlert(const nsAString
& aAlertName
) {
613 RefPtr
<ToastNotificationHandler
> handler
;
614 if (NS_WARN_IF(!mActiveHandlers
.Get(aAlertName
, getter_AddRefs(handler
)))) {
617 mActiveHandlers
.Remove(aAlertName
);
618 handler
->UnregisterHandler();
622 bool ToastNotification::IsActiveHandler(const nsAString
& aAlertName
,
623 ToastNotificationHandler
* aHandler
) {
624 RefPtr
<ToastNotificationHandler
> handler
;
625 if (NS_WARN_IF(!mActiveHandlers
.Get(aAlertName
, getter_AddRefs(handler
)))) {
628 return handler
== aHandler
;
631 void ToastNotification::RemoveHandler(const nsAString
& aAlertName
,
632 ToastNotificationHandler
* aHandler
) {
633 // The alert may have been replaced; only remove it from the active
634 // handler's map if it's the same.
635 if (IsActiveHandler(aAlertName
, aHandler
)) {
636 // Terrible things happen if the destructor of a handler is called inside
637 // the hashtable .Remove() method. Wait until we have returned from there.
638 RefPtr
<ToastNotificationHandler
> kungFuDeathGrip(aHandler
);
639 mActiveHandlers
.Remove(aAlertName
);
640 aHandler
->UnregisterHandler();
645 ToastNotification::RemoveAllNotificationsForInstall() {
648 ComPtr
<IToastNotificationManagerStatics
> manager
;
649 hr
= GetActivationFactory(
651 RuntimeClass_Windows_UI_Notifications_ToastNotificationManager
)
654 NS_ENSURE_TRUE(SUCCEEDED(hr
), NS_ERROR_FAILURE
);
657 MOZ_ASSERT(mAumid
.isSome());
658 hr
= aumid
.Set(mAumid
.ref().get());
659 NS_ENSURE_TRUE(SUCCEEDED(hr
), NS_ERROR_FAILURE
);
661 // Hide toasts in action center.
663 ComPtr
<IToastNotificationManagerStatics2
> manager2
;
664 hr
= manager
.As(&manager2
);
665 NS_ENSURE_TRUE_VOID(SUCCEEDED(hr
));
667 ComPtr
<IToastNotificationHistory
> history
;
668 hr
= manager2
->get_History(&history
);
669 NS_ENSURE_TRUE_VOID(SUCCEEDED(hr
));
671 hr
= history
->ClearWithId(aumid
.Get());
672 NS_ENSURE_TRUE_VOID(SUCCEEDED(hr
));
675 // Hide scheduled toasts.
677 ComPtr
<IToastNotifier
> notifier
;
678 hr
= manager
->CreateToastNotifierWithId(aumid
.Get(), ¬ifier
);
679 NS_ENSURE_TRUE_VOID(SUCCEEDED(hr
));
681 ComPtr
<IVectorView_ScheduledToastNotification
> scheduledToasts
;
682 hr
= notifier
->GetScheduledToastNotifications(&scheduledToasts
);
683 NS_ENSURE_TRUE_VOID(SUCCEEDED(hr
));
685 unsigned int schedSize
;
686 hr
= scheduledToasts
->get_Size(&schedSize
);
687 NS_ENSURE_TRUE_VOID(SUCCEEDED(hr
));
689 for (unsigned int i
= 0; i
< schedSize
; i
++) {
690 ComPtr
<IScheduledToastNotification
> schedToast
;
691 hr
= scheduledToasts
->GetAt(i
, &schedToast
);
692 if (NS_WARN_IF(FAILED(hr
))) {
696 hr
= notifier
->RemoveFromSchedule(schedToast
.Get());
697 Unused
<< NS_WARN_IF(FAILED(hr
));
704 } // namespace widget
705 } // namespace mozilla