diff --git a/dev/AppLifecycle/ActivationRegistrationManager.h b/dev/AppLifecycle/ActivationRegistrationManager.h index 04cbb3b560..374586308e 100644 --- a/dev/AppLifecycle/ActivationRegistrationManager.h +++ b/dev/AppLifecycle/ActivationRegistrationManager.h @@ -11,6 +11,7 @@ namespace winrt::Microsoft::Windows::AppLifecycle::implementation static PCWSTR c_argumentSuffix{ L":" }; static PCWSTR c_msProtocolArgumentString{ L"ms-protocol" }; static PCWSTR c_pushProtocolArgumentString{ L"WindowsAppRuntimePushServer" }; + static PCWSTR c_toastProtocolArgumentString{ L"AppNotificationActivated" }; static PCWSTR c_runKeyPath{ LR"(Software\Microsoft\Windows\CurrentVersion\Run\)" }; struct ActivationRegistrationManager diff --git a/dev/AppLifecycle/AppInstance.cpp b/dev/AppLifecycle/AppInstance.cpp index ae6b2cf78c..303c331204 100644 --- a/dev/AppLifecycle/AppInstance.cpp +++ b/dev/AppLifecycle/AppInstance.cpp @@ -12,7 +12,7 @@ #include "FileActivatedEventArgs.h" #include "Association.h" #include "ExtensionContract.h" -#include "GetRawNotificationEventArgs.h" +#include "GetNotificationEventArgs.h" using namespace winrt; using namespace winrt::Windows::Foundation; @@ -376,10 +376,12 @@ namespace winrt::Microsoft::Windows::AppLifecycle::implementation // protocol, except the catch-all LaunchActivatedEventArgs case. if (!contractArgument.empty()) { - if (contractArgument == c_pushProtocolArgumentString) + if (contractArgument == c_pushProtocolArgumentString || contractArgument == c_toastProtocolArgumentString) { - // Generate a basic encoded launch Uri for all Push activations. - std::wstring tempContractData = GenerateEncodedLaunchUri(L"App", c_pushContractId); + // Generate a basic encoded launch Uri for Push/Toast activations + PCWSTR contractId = (contractArgument == c_pushProtocolArgumentString) ? c_pushContractId : c_toastContractId; + std::wstring tempContractData = GenerateEncodedLaunchUri(L"App", contractId); + contractArgument = c_msProtocolArgumentString; // A non-empty contractData means we have a payload. diff --git a/dev/AppLifecycle/AppLifecycle.idl b/dev/AppLifecycle/AppLifecycle.idl index e63734efd5..644d3a91f2 100644 --- a/dev/AppLifecycle/AppLifecycle.idl +++ b/dev/AppLifecycle/AppLifecycle.idl @@ -53,6 +53,7 @@ namespace Microsoft.Windows.AppLifecycle // Windows.ApplicationModel.Activation.ActivationKind. Push = 5000, + AppNotification, }; runtimeclass AppActivationArguments diff --git a/dev/AppLifecycle/ExtensionContract.h b/dev/AppLifecycle/ExtensionContract.h index f4789ffab9..74c42d3b0d 100644 --- a/dev/AppLifecycle/ExtensionContract.h +++ b/dev/AppLifecycle/ExtensionContract.h @@ -7,7 +7,7 @@ #include "ProtocolActivatedEventArgs.h" #include "FileActivatedEventArgs.h" #include "StartupActivatedEventArgs.h" -#include "GetRawNotificationEventArgs.h" +#include "GetNotificationEventArgs.h" namespace winrt::Microsoft::Windows::AppLifecycle::implementation { @@ -26,6 +26,7 @@ namespace winrt::Microsoft::Windows::AppLifecycle::implementation { ExtendedActivationKind::Protocol, c_protocolContractId, &ProtocolActivatedEventArgs::Deserialize }, { ExtendedActivationKind::StartupTask, c_startupTaskContractId, &StartupActivatedEventArgs::Deserialize }, { ExtendedActivationKind::Push, c_pushContractId, &winrt::Microsoft::Windows::PushNotifications::Deserialize }, + { ExtendedActivationKind::AppNotification, c_toastContractId, &winrt::Microsoft::Windows::PushNotifications::Deserialize }, }; inline bool IsEncodedLaunch(winrt::Windows::Foundation::Uri const& uri) diff --git a/dev/PushNotifications/GetRawNotificationEventArgs.h b/dev/PushNotifications/GetNotificationEventArgs.h similarity index 79% rename from dev/PushNotifications/GetRawNotificationEventArgs.h rename to dev/PushNotifications/GetNotificationEventArgs.h index 2bf1bdd683..df8b44c146 100644 --- a/dev/PushNotifications/GetRawNotificationEventArgs.h +++ b/dev/PushNotifications/GetNotificationEventArgs.h @@ -7,6 +7,7 @@ #include "externs.h" constexpr PCWSTR c_pushContractId = L"Windows.Push"; +constexpr PCWSTR c_toastContractId = L"Windows.Toast"; namespace winrt::Microsoft::Windows::PushNotifications { @@ -25,11 +26,6 @@ namespace winrt::Microsoft::Windows::PushNotifications return winrt::make(payloadAsWstring); } } - - const DWORD receiveArgsTimeoutInMSec{ 2000 }; - THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_TIMEOUT), !GetWaitHandleForArgs().wait(receiveArgsTimeoutInMSec)); - - // If COM static store was uninit, let it throw - return winrt::Windows::ApplicationModel::Core::CoreApplication::Properties().Lookup(ACTIVATED_EVENT_ARGS_KEY); + return GetArgsFromComStore(); } } diff --git a/dev/PushNotifications/PushNotifications.vcxitems b/dev/PushNotifications/PushNotifications.vcxitems index 5f0fb92680..3e6d5a339d 100644 --- a/dev/PushNotifications/PushNotifications.vcxitems +++ b/dev/PushNotifications/PushNotifications.vcxitems @@ -26,7 +26,7 @@ - + diff --git a/dev/PushNotifications/externs.h b/dev/PushNotifications/externs.h index 2217362df3..d0eb2d1b58 100644 --- a/dev/PushNotifications/externs.h +++ b/dev/PushNotifications/externs.h @@ -3,6 +3,7 @@ #pragma once #include "pch.h" +#include wil::unique_event& GetWaitHandleForArgs(); @@ -20,3 +21,12 @@ inline HRESULT GetCurrentProcessPath(wil::unique_cotaskmem_string& processName) { return wil::GetModuleFileNameExW(GetCurrentProcess(), nullptr, processName); }; + +inline winrt::Windows::Foundation::IInspectable GetArgsFromComStore() +{ + const DWORD receiveArgsTimeoutInMSec{ 2000 }; + THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_TIMEOUT), !GetWaitHandleForArgs().wait(receiveArgsTimeoutInMSec)); + + // If COM static store was uninit, let it throw + return winrt::Windows::ApplicationModel::Core::CoreApplication::Properties().Lookup(ACTIVATED_EVENT_ARGS_KEY); +} diff --git a/dev/ToastNotifications/ToastActivationCallback.h b/dev/ToastNotifications/ToastActivationCallback.h index 257394bb61..c13c7c3497 100644 --- a/dev/ToastNotifications/ToastActivationCallback.h +++ b/dev/ToastNotifications/ToastActivationCallback.h @@ -18,7 +18,7 @@ struct ToastActivationCallbackFactory : winrt::implements().as(interfaceId, object); } CATCH_RETURN() diff --git a/dev/ToastNotifications/ToastNotificationManager.cpp b/dev/ToastNotifications/ToastNotificationManager.cpp index b6596a75ed..523403188f 100644 --- a/dev/ToastNotifications/ToastNotificationManager.cpp +++ b/dev/ToastNotifications/ToastNotificationManager.cpp @@ -74,13 +74,13 @@ namespace winrt::Microsoft::Windows::ToastNotifications::implementation // TODO: Remove ToastGuid reference from LRP } } - winrt::event_token ToastNotificationManager::ToastActivated(winrt::Windows::Foundation::EventHandler const& /* handler */) + winrt::event_token ToastNotificationManager::ToastActivated(winrt::Windows::Foundation::EventHandler const& handler) { - throw hresult_not_implemented(); + return GetToastHandlers().add(handler); } - void ToastNotificationManager::ToastActivated(winrt::event_token const&/* token */) + void ToastNotificationManager::ToastActivated(winrt::event_token const& token) { - throw hresult_not_implemented(); + GetToastHandlers().remove(token); } void ToastNotificationManager::ShowToast(winrt::Microsoft::Windows::ToastNotifications::ToastNotification const& /* toast */) { diff --git a/dev/ToastNotifications/ToastNotificationUtility.h b/dev/ToastNotifications/ToastNotificationUtility.h index 4e546b343e..2ca4d2f630 100644 --- a/dev/ToastNotifications/ToastNotificationUtility.h +++ b/dev/ToastNotifications/ToastNotificationUtility.h @@ -9,7 +9,7 @@ const std::wstring c_appIdentifierPath{ LR"(Software\Classes\AppUserModelId\)" }; const std::wstring c_clsIdPath{ LR"(Software\Classes\CLSID\)" }; const std::wstring c_quote{ LR"(")" }; -const std::wstring c_toastActivatedArgument{ L" ----ToastActivated:" }; +const std::wstring c_toastActivatedArgument{ L" ----AppNotificationActivated:" }; winrt::event>& GetToastHandlers(); diff --git a/test/TestApps/ToastNotificationsTestApp/main.cpp b/test/TestApps/ToastNotificationsTestApp/main.cpp index dcfabe0358..01c822d2c5 100644 --- a/test/TestApps/ToastNotificationsTestApp/main.cpp +++ b/test/TestApps/ToastNotificationsTestApp/main.cpp @@ -12,6 +12,17 @@ namespace winrt using namespace winrt::Microsoft::Windows::ToastNotifications; } +bool BackgroundActivationTest() // Activating application for background test. +{ + return true; +} + +bool UnregisterBackgroundActivationTest() +{ + winrt::ToastNotificationManager::Default().UnregisterActivator(); + return true; +} + bool VerifyFailedRegisterActivatorUsingNullClsid() { try @@ -78,12 +89,19 @@ bool VerifyFailedRegisterActivatorUsingNullAssets_Unpackaged() bool VerifyRegisterActivatorandUnRegisterActivatorUsingClsid() { - auto activationInfo = winrt::ToastActivationInfo::CreateFromActivationGuid(winrt::guid("1940DBA9-0F64-4F0D-8A4B-5D207B812E61")); - - winrt::ToastNotificationManager::Default().RegisterActivator(activationInfo); - winrt::ToastNotificationManager::Default().UnregisterActivator(); + try + { + auto activationInfo = winrt::ToastActivationInfo::CreateFromActivationGuid(c_toastComServerId); + + winrt::ToastNotificationManager::Default().RegisterActivator(activationInfo); + winrt::ToastNotificationManager::Default().UnregisterActivator(); + } + catch (...) + { + return false; + } return true; } @@ -104,7 +122,7 @@ bool VerifyFailedMultipleRegisterActivatorUsingSameClsid() { try { - auto activationInfo = winrt::ToastActivationInfo::CreateFromActivationGuid(winrt::guid("1940DBA9-0F64-4F0D-8A4B-5D207B812E61")); + auto activationInfo = winrt::ToastActivationInfo::CreateFromActivationGuid(c_toastComServerId); winrt::ToastNotificationManager::Default().RegisterActivator(activationInfo); @@ -201,9 +219,12 @@ std::string unitTestNameFromLaunchArguments(const winrt::ILaunchActivatedEventAr std::map const& GetSwitchMapping() { static std::map switchMapping = { + { "BackgroundActivationTest", &BackgroundActivationTest}, + { "UnregisterBackgroundActivationTest", &UnregisterBackgroundActivationTest}, { "VerifyFailedRegisterActivatorUsingNullClsid", &VerifyFailedRegisterActivatorUsingNullClsid }, { "VerifyFailedRegisterActivatorUsingNullClsid_Unpackaged", &VerifyFailedRegisterActivatorUsingNullClsid_Unpackaged}, { "VerifyFailedRegisterActivatorUsingNullAssets", &VerifyFailedRegisterActivatorUsingNullAssets }, + { "VerifyFailedRegisterActivatorUsingNullAssets_Unpackaged", &VerifyFailedRegisterActivatorUsingNullAssets_Unpackaged}, { "VerifyRegisterActivatorandUnRegisterActivatorUsingClsid", &VerifyRegisterActivatorandUnRegisterActivatorUsingClsid }, { "VerifyRegisterActivatorandUnRegisterActivatorUsingAssets_Unpackaged", &VerifyRegisterActivatorandUnRegisterActivatorUsingAssets_Unpackaged }, { "VerifyFailedMultipleRegisterActivatorUsingSameClsid", &VerifyFailedMultipleRegisterActivatorUsingSameClsid }, @@ -237,6 +258,12 @@ int main() try ::Test::Bootstrap::SetupBootstrap(); + if (Test::AppModel::IsPackagedProcess()) + { + auto activationInfo = winrt::ToastActivationInfo::CreateFromActivationGuid(c_toastComServerId); + winrt::ToastNotificationManager::Default().RegisterActivator(activationInfo); + } + auto args = winrt::AppInstance::GetCurrent().GetActivatedEventArgs(); auto kind = args.Kind(); diff --git a/test/TestApps/ToastNotificationsTestAppPackage/Package.appxmanifest b/test/TestApps/ToastNotificationsTestAppPackage/Package.appxmanifest index 82398d33c4..a8887425b4 100644 --- a/test/TestApps/ToastNotificationsTestAppPackage/Package.appxmanifest +++ b/test/TestApps/ToastNotificationsTestAppPackage/Package.appxmanifest @@ -50,7 +50,7 @@ - + diff --git a/test/ToastNotificationTests/APITests.cpp b/test/ToastNotificationTests/APITests.cpp index f1e9a9ed52..af6af609d1 100644 --- a/test/ToastNotificationTests/APITests.cpp +++ b/test/ToastNotificationTests/APITests.cpp @@ -1,4 +1,5 @@ #include "pch.h" +#include "NotificationActivationCallback.h" #include using namespace WEX::Common; @@ -158,6 +159,16 @@ namespace Test::ToastNotifications VERIFY_ARE_EQUAL(exitCode, 0); } + TEST_METHOD(VerifyBackgroundActivation) + { + RunTest(L"BackgroundActivationTest", testWaitTime()); // Need to launch one time to enable background activation. + + auto toastActivationCallback = winrt::create_instance(c_toastComServerId, CLSCTX_ALL); + VERIFY_SUCCEEDED(toastActivationCallback->Activate(L"AUMID", L"args", nullptr, 0)); + + RunTest(L"UnregisterBackgroundActivationTest", testWaitTime()); // Need to launch again to unregister activation + } + TEST_METHOD(VerifyFailedRegisterActivatorUsingNullClsid) { RunTest(L"VerifyFailedRegisterActivatorUsingNullClsid", testWaitTime()); diff --git a/test/inc/TestDef.h b/test/inc/TestDef.h index 93a41cbb2a..f472c82774 100644 --- a/test/inc/TestDef.h +++ b/test/inc/TestDef.h @@ -20,6 +20,7 @@ static const std::wstring c_testInstanceRedirectedPhaseEventName = L"WindowsAppR static const std::wstring c_testPushPhaseEventName = L"WindowsAppRuntimeTestPushPhaseEventName"; inline const winrt::hstring c_rawNotificationPayload = L""; inline IID c_comServerId = winrt::guid("ccd2ae3f-764f-4ae3-be45-9804761b28b2"); // Value from PushNotificationsTestAppPackage ComActivator in appxmanifest. +inline IID c_toastComServerId = winrt::guid("1940dba9-0f64-4f0d-8a4b-5d207b812e61"); // Value from ToastNotificationsTestAppPackage ComActivator in appxmanifest. inline IID c_fakeComServerId = winrt::guid("00000000-0000-0000-0000-000000000001"); #ifndef WIDEN2