summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/defaultagent/Notification.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/defaultagent/Notification.cpp')
-rw-r--r--toolkit/mozapps/defaultagent/Notification.cpp602
1 files changed, 4 insertions, 598 deletions
diff --git a/toolkit/mozapps/defaultagent/Notification.cpp b/toolkit/mozapps/defaultagent/Notification.cpp
index 961e57c9b3..39236eac15 100644
--- a/toolkit/mozapps/defaultagent/Notification.cpp
+++ b/toolkit/mozapps/defaultagent/Notification.cpp
@@ -7,616 +7,22 @@
#include "Notification.h"
#include <shlwapi.h>
-#include <wchar.h>
#include <windows.h>
#include <winnt.h>
-#include "mozilla/ArrayUtils.h"
-#include "mozilla/CmdLineAndEnvUtils.h"
-#include "mozilla/ErrorResult.h"
-#include "mozilla/mscom/EnsureMTA.h"
-#include "mozilla/intl/FileSource.h"
-#include "mozilla/intl/Localization.h"
-#include "mozilla/ShellHeaderOnlyUtils.h"
-#include "mozilla/UniquePtr.h"
-#include "mozilla/Unused.h"
-#include "mozilla/WinHeaderOnlyUtils.h"
-#include "nsString.h"
-#include "nsTArray.h"
-#include "nsWindowsHelpers.h"
-#include "readstrings.h"
-#include "updatererrors.h"
-#include "WindowsDefaultBrowser.h"
-
-#include "common.h"
-#include "DefaultBrowser.h"
-#include "EventLog.h"
-#include "Registry.h"
-#include "SetDefaultBrowser.h"
-
-#include "wintoastlib.h"
-
-using mozilla::intl::Localization;
+#include "nsLiteralString.h"
#define SEVEN_DAYS_IN_SECONDS (7 * 24 * 60 * 60)
-// If the notification hasn't been activated or dismissed within 12 hours,
-// stop waiting for it.
-#define NOTIFICATION_WAIT_TIMEOUT_MS (12 * 60 * 60 * 1000)
+// If the notification hasn't been activated or dismissed within 11 hours 55
+// minutes, stop waiting for it.
+#define NOTIFICATION_WAIT_TIMEOUT_MS (11 * 60 * 60 * 1000 + 55 * 60 * 1000)
// If the mutex hasn't been released within a few minutes, something is wrong
// and we should give up on it
#define MUTEX_TIMEOUT_MS (10 * 60 * 1000)
namespace mozilla::default_agent {
-bool FirefoxInstallIsEnglish();
-
-static bool SetInitialNotificationShown(bool wasShown) {
- return !RegistrySetValueBool(IsPrefixed::Unprefixed,
- L"InitialNotificationShown", wasShown)
- .isErr();
-}
-
-static bool GetInitialNotificationShown() {
- return RegistryGetValueBool(IsPrefixed::Unprefixed,
- L"InitialNotificationShown")
- .unwrapOr(mozilla::Some(false))
- .valueOr(false);
-}
-
-static bool ResetInitialNotificationShown() {
- return RegistryDeleteValue(IsPrefixed::Unprefixed,
- L"InitialNotificationShown")
- .isOk();
-}
-
-static bool SetFollowupNotificationShown(bool wasShown) {
- return !RegistrySetValueBool(IsPrefixed::Unprefixed,
- L"FollowupNotificationShown", wasShown)
- .isErr();
-}
-
-static bool GetFollowupNotificationShown() {
- return RegistryGetValueBool(IsPrefixed::Unprefixed,
- L"FollowupNotificationShown")
- .unwrapOr(mozilla::Some(false))
- .valueOr(false);
-}
-
-static bool SetFollowupNotificationSuppressed(bool value) {
- return !RegistrySetValueBool(IsPrefixed::Unprefixed,
- L"FollowupNotificationSuppressed", value)
- .isErr();
-}
-
-static bool GetFollowupNotificationSuppressed() {
- return RegistryGetValueBool(IsPrefixed::Unprefixed,
- L"FollowupNotificationSuppressed")
- .unwrapOr(mozilla::Some(false))
- .valueOr(false);
-}
-
-// Returns 0 if no value is set.
-static ULONGLONG GetFollowupNotificationRequestTime() {
- return RegistryGetValueQword(IsPrefixed::Unprefixed, L"FollowupRequestTime")
- .unwrapOr(mozilla::Some(0))
- .valueOr(0);
-}
-
-// Returns false if no value is set.
-static bool GetPrefSetDefaultBrowserUserChoice() {
- return RegistryGetValueBool(IsPrefixed::Prefixed,
- L"SetDefaultBrowserUserChoice")
- .unwrapOr(mozilla::Some(false))
- .valueOr(false);
-}
-
-struct ToastStrings {
- mozilla::UniquePtr<wchar_t[]> text1;
- mozilla::UniquePtr<wchar_t[]> text2;
- mozilla::UniquePtr<wchar_t[]> action1;
- mozilla::UniquePtr<wchar_t[]> action2;
- mozilla::UniquePtr<wchar_t[]> relImagePath;
-};
-
-struct Strings {
- // Toast notification button text is hard to localize because it tends to
- // overflow. Thus, we have 3 different toast notifications:
- // - The initial notification, which includes a button with text like
- // "Ask me later". Since we cannot easily localize this, we will display
- // it only in English.
- // - The followup notification, to be shown if the user clicked "Ask me
- // later". Since we only have that button in English, we only need this
- // notification in English.
- // - The localized notification, which has much shorter button text to
- // (hopefully) prevent overflow: just "Yes" and "No". Since we no longer
- // have an "Ask me later" button, a followup localized notification is not
- // needed.
- ToastStrings initialToast;
- ToastStrings followupToast;
- ToastStrings localizedToast;
-
- // Returned pointer points within this struct and should not be freed.
- const ToastStrings* GetToastStrings(NotificationType whichToast,
- bool englishStrings) const {
- if (!englishStrings) {
- return &localizedToast;
- }
- if (whichToast == NotificationType::Initial) {
- return &initialToast;
- }
- return &followupToast;
- }
-};
-
-// Gets all strings out of the relevant INI files.
-// Returns true on success, false on failure
-static bool GetStrings(Strings& strings) {
- mozilla::UniquePtr<wchar_t[]> installPath;
- bool success = GetInstallDirectory(installPath);
- if (!success) {
- LOG_ERROR_MESSAGE(L"Failed to get install directory when getting strings");
- return false;
- }
- nsTArray<nsCString> resIds = {"branding/brand.ftl"_ns,
- "browser/backgroundtasks/defaultagent.ftl"_ns};
- RefPtr<Localization> l10n = Localization::Create(resIds, true);
- nsAutoCString daHeaderText, daBodyText, daYesButton, daNoButton;
- mozilla::ErrorResult daRv;
- l10n->FormatValueSync("default-browser-notification-header-text"_ns, {},
- daHeaderText, daRv);
- ENSURE_SUCCESS(daRv, false);
- l10n->FormatValueSync("default-browser-notification-body-text"_ns, {},
- daBodyText, daRv);
- ENSURE_SUCCESS(daRv, false);
- l10n->FormatValueSync("default-browser-notification-yes-button-text"_ns, {},
- daYesButton, daRv);
- ENSURE_SUCCESS(daRv, false);
- l10n->FormatValueSync("default-browser-notification-no-button-text"_ns, {},
- daNoButton, daRv);
- ENSURE_SUCCESS(daRv, false);
-
- NS_ConvertUTF8toUTF16 daHeaderTextW(daHeaderText), daBodyTextW(daBodyText),
- daYesButtonW(daYesButton), daNoButtonW(daNoButton);
- strings.localizedToast.text1 =
- mozilla::MakeUnique<wchar_t[]>(daHeaderTextW.Length() + 1);
- wcsncpy(strings.localizedToast.text1.get(), daHeaderTextW.get(),
- daHeaderTextW.Length() + 1);
- strings.localizedToast.text2 =
- mozilla::MakeUnique<wchar_t[]>(daBodyTextW.Length() + 1);
- wcsncpy(strings.localizedToast.text2.get(), daBodyTextW.get(),
- daBodyTextW.Length() + 1);
- strings.localizedToast.action1 =
- mozilla::MakeUnique<wchar_t[]>(daYesButtonW.Length() + 1);
- wcsncpy(strings.localizedToast.action1.get(), daYesButtonW.get(),
- daYesButtonW.Length() + 1);
- strings.localizedToast.action2 =
- mozilla::MakeUnique<wchar_t[]>(daNoButtonW.Length() + 1);
- wcsncpy(strings.localizedToast.action2.get(), daNoButtonW.get(),
- daNoButtonW.Length() + 1);
- const wchar_t* iniFormat = L"%s\\defaultagent.ini";
- int bufferSize = _scwprintf(iniFormat, installPath.get());
- ++bufferSize; // Extra character for terminating null
- mozilla::UniquePtr<wchar_t[]> iniPath =
- mozilla::MakeUnique<wchar_t[]>(bufferSize);
- _snwprintf_s(iniPath.get(), bufferSize, _TRUNCATE, iniFormat,
- installPath.get());
-
- IniReader nonlocalizedReader(iniPath.get(), "Nonlocalized");
- nonlocalizedReader.AddKey("InitialToastRelativeImagePath",
- &strings.initialToast.relImagePath);
- nonlocalizedReader.AddKey("FollowupToastRelativeImagePath",
- &strings.followupToast.relImagePath);
- nonlocalizedReader.AddKey("LocalizedToastRelativeImagePath",
- &strings.localizedToast.relImagePath);
- int result = nonlocalizedReader.Read();
- if (result != OK) {
- LOG_ERROR_MESSAGE(L"Unable to read non-localized strings: %d", result);
- return false;
- }
-
- return true;
-}
-
-static mozilla::WindowsError LaunchFirefoxToHandleDefaultBrowserAgent() {
- // Could also be `MOZ_APP_NAME.exe`, but there's no generality to be gained:
- // the WDBA is Firefox-only.
- FilePathResult firefoxPathResult = GetRelativeBinaryPath(L"firefox.exe");
- if (firefoxPathResult.isErr()) {
- return firefoxPathResult.unwrapErr();
- }
- std::wstring firefoxPath = firefoxPathResult.unwrap();
-
- _bstr_t cmd = firefoxPath.c_str();
- // Omit argv[0] because ShellExecute doesn't need it.
- _variant_t args(L"-to-handle-default-browser-agent");
- _variant_t operation(L"open");
- _variant_t directory;
- _variant_t showCmd(SW_SHOWNORMAL);
-
- // To prevent inheriting environment variables from the background task, we
- // run Firefox via Explorer instead of our own process. This mimics the
- // implementation of the Windows Launcher Process.
- auto result =
- ShellExecuteByExplorer(cmd, args, operation, directory, showCmd);
- NS_ENSURE_TRUE(result.isOk(), result.unwrapErr());
-
- return mozilla::WindowsError::CreateSuccess();
-}
-
-/*
- * Set the default browser.
- *
- * First check if we can directly write UserChoice, if so attempt that.
- * If we can't write UserChoice, or if the attempt fails, fall back to
- * showing the Default Apps page of Settings.
- *
- * @param aAumi The AUMI of the installation to set as default.
- */
-static void SetDefaultBrowserFromNotification(const wchar_t* aumi) {
- nsresult rv = NS_ERROR_FAILURE;
- if (GetPrefSetDefaultBrowserUserChoice()) {
- rv = SetDefaultBrowserUserChoice(aumi);
- }
-
- if (NS_SUCCEEDED(rv)) {
- mozilla::Unused << LaunchFirefoxToHandleDefaultBrowserAgent();
- } else {
- LOG_ERROR_MESSAGE(L"Failed to SetDefaultBrowserUserChoice: %#X",
- GetLastError());
- LaunchModernSettingsDialogDefaultApps();
- }
-}
-
-// This encapsulates the data that needs to be protected by a mutex because it
-// will be shared by the main thread and the handler thread.
-// To ensure the data is only written once, handlerDataHasBeenSet should be
-// initialized to false, then set to true when the handler writes data into the
-// structure.
-struct HandlerData {
- NotificationActivities activitiesPerformed;
- bool handlerDataHasBeenSet;
-};
-
-// The value that ToastHandler writes into should be a global. We can't control
-// when ToastHandler is called, and if this value isn't a global, ToastHandler
-// may be called and attempt to access this after it has been deconstructed.
-// Since this value is accessed by the handler thread and the main thread, it
-// is protected by a mutex (gHandlerMutex).
-// Since ShowNotification deconstructs the mutex, it might seem like once
-// ShowNotification exits, we can just rely on the inability to wait on an
-// invalid mutex to protect the deconstructed data, but it's possible that
-// we could deconstruct the mutex while the handler is holding it and is
-// already accessing the protected data.
-static HandlerData gHandlerReturnData;
-static HANDLE gHandlerMutex = INVALID_HANDLE_VALUE;
-
-class ToastHandler : public WinToastLib::IWinToastHandler {
- private:
- NotificationType mWhichNotification;
- HANDLE mEvent;
- const std::wstring mAumiStr;
-
- public:
- ToastHandler(NotificationType whichNotification, HANDLE event,
- const wchar_t* aumi)
- : mWhichNotification(whichNotification), mEvent(event), mAumiStr(aumi) {}
-
- void FinishHandler(NotificationActivities& returnData) const {
- SetReturnData(returnData);
-
- BOOL success = SetEvent(mEvent);
- if (!success) {
- LOG_ERROR_MESSAGE(L"Event could not be set: %#X", GetLastError());
- }
- }
-
- void SetReturnData(NotificationActivities& toSet) const {
- DWORD result = WaitForSingleObject(gHandlerMutex, MUTEX_TIMEOUT_MS);
- if (result == WAIT_TIMEOUT) {
- LOG_ERROR_MESSAGE(L"Unable to obtain mutex ownership");
- return;
- } else if (result == WAIT_FAILED) {
- LOG_ERROR_MESSAGE(L"Failed to wait on mutex: %#X", GetLastError());
- return;
- } else if (result == WAIT_ABANDONED) {
- LOG_ERROR_MESSAGE(L"Found abandoned mutex");
- ReleaseMutex(gHandlerMutex);
- return;
- }
-
- // Only set this data once
- if (!gHandlerReturnData.handlerDataHasBeenSet) {
- gHandlerReturnData.activitiesPerformed = toSet;
- gHandlerReturnData.handlerDataHasBeenSet = true;
- }
-
- BOOL success = ReleaseMutex(gHandlerMutex);
- if (!success) {
- LOG_ERROR_MESSAGE(L"Unable to release mutex ownership: %#X",
- GetLastError());
- }
- }
-
- void toastActivated() const override {
- NotificationActivities activitiesPerformed;
- activitiesPerformed.type = mWhichNotification;
- activitiesPerformed.shown = NotificationShown::Shown;
- activitiesPerformed.action = NotificationAction::ToastClicked;
-
- // Notification strings are written to indicate the default browser is
- // restored to Firefox when the notification body is clicked to prevent
- // ambiguity when buttons aren't pressed.
- SetDefaultBrowserFromNotification(mAumiStr.c_str());
-
- FinishHandler(activitiesPerformed);
- }
-
- void toastActivated(int actionIndex) const override {
- NotificationActivities activitiesPerformed;
- activitiesPerformed.type = mWhichNotification;
- activitiesPerformed.shown = NotificationShown::Shown;
- // Override this below
- activitiesPerformed.action = NotificationAction::NoAction;
-
- if (actionIndex == 0) {
- // "Make Firefox the default" button, on both the initial and followup
- // notifications. "Yes" button on the localized notification.
- activitiesPerformed.action = NotificationAction::MakeFirefoxDefaultButton;
-
- SetDefaultBrowserFromNotification(mAumiStr.c_str());
- } else if (actionIndex == 1) {
- // Do nothing. As long as we don't call
- // SetFollowupNotificationRequestTime, there will be no followup
- // notification.
- activitiesPerformed.action = NotificationAction::DismissedByButton;
- }
-
- FinishHandler(activitiesPerformed);
- }
-
- void toastDismissed(WinToastDismissalReason state) const override {
- NotificationActivities activitiesPerformed;
- activitiesPerformed.type = mWhichNotification;
- activitiesPerformed.shown = NotificationShown::Shown;
- // Override this below
- activitiesPerformed.action = NotificationAction::NoAction;
-
- if (state == WinToastDismissalReason::TimedOut) {
- activitiesPerformed.action = NotificationAction::DismissedByTimeout;
- } else if (state == WinToastDismissalReason::ApplicationHidden) {
- activitiesPerformed.action =
- NotificationAction::DismissedByApplicationHidden;
- } else if (state == WinToastDismissalReason::UserCanceled) {
- activitiesPerformed.action = NotificationAction::DismissedToActionCenter;
- }
-
- FinishHandler(activitiesPerformed);
- }
-
- void toastFailed() const override {
- NotificationActivities activitiesPerformed;
- activitiesPerformed.type = mWhichNotification;
- activitiesPerformed.shown = NotificationShown::Error;
- activitiesPerformed.action = NotificationAction::NoAction;
-
- LOG_ERROR_MESSAGE(L"Toast notification failed to display");
- FinishHandler(activitiesPerformed);
- }
-};
-
-// This function blocks until the shown notification is activated or dismissed.
-static NotificationActivities ShowNotification(
- NotificationType whichNotification, const wchar_t* aumi) {
- // Initially set the value that will be returned to error. If the notification
- // is shown successfully, we'll update it.
- NotificationActivities activitiesPerformed = {whichNotification,
- NotificationShown::Error,
- NotificationAction::NoAction};
-
- bool isEnglishInstall = FirefoxInstallIsEnglish();
-
- Strings strings;
- if (!GetStrings(strings)) {
- return activitiesPerformed;
- }
- const ToastStrings* toastStrings =
- strings.GetToastStrings(whichNotification, isEnglishInstall);
-
- mozilla::mscom::EnsureMTA([&] {
- using namespace WinToastLib;
-
- if (!WinToast::isCompatible()) {
- LOG_ERROR_MESSAGE(L"System is not compatible with WinToast");
- return;
- }
- WinToast::instance()->setAppName(L"" MOZ_APP_DISPLAYNAME);
- std::wstring aumiStr = aumi;
- WinToast::instance()->setAppUserModelId(aumiStr);
- WinToast::instance()->setShortcutPolicy(
- WinToastLib::WinToast::SHORTCUT_POLICY_REQUIRE_NO_CREATE);
- WinToast::WinToastError error;
- if (!WinToast::instance()->initialize(&error)) {
- LOG_ERROR_MESSAGE(WinToast::strerror(error).c_str());
- return;
- }
-
- // This event object will let the handler notify us when it has handled the
- // notification.
- nsAutoHandle event(CreateEventW(nullptr, TRUE, FALSE, nullptr));
- if (event.get() == nullptr) {
- LOG_ERROR_MESSAGE(L"Unable to create event object: %#X", GetLastError());
- return;
- }
-
- bool success = false;
- if (whichNotification == NotificationType::Initial) {
- success = SetInitialNotificationShown(true);
- } else {
- success = SetFollowupNotificationShown(true);
- }
- if (!success) {
- // Return early in this case to prevent the notification from being shown
- // on every run.
- LOG_ERROR_MESSAGE(L"Unable to set notification as displayed");
- return;
- }
-
- // We need the absolute image path, not the relative path.
- mozilla::UniquePtr<wchar_t[]> installPath;
- success = GetInstallDirectory(installPath);
- if (!success) {
- LOG_ERROR_MESSAGE(L"Failed to get install directory for the image path");
- return;
- }
- const wchar_t* absPathFormat = L"%s\\%s";
- int bufferSize = _scwprintf(absPathFormat, installPath.get(),
- toastStrings->relImagePath.get());
- ++bufferSize; // Extra character for terminating null
- mozilla::UniquePtr<wchar_t[]> absImagePath =
- mozilla::MakeUnique<wchar_t[]>(bufferSize);
- _snwprintf_s(absImagePath.get(), bufferSize, _TRUNCATE, absPathFormat,
- installPath.get(), toastStrings->relImagePath.get());
-
- // This is used to protect gHandlerReturnData.
- gHandlerMutex = CreateMutexW(nullptr, TRUE, nullptr);
- if (gHandlerMutex == nullptr) {
- LOG_ERROR_MESSAGE(L"Unable to create mutex: %#X", GetLastError());
- return;
- }
- // Automatically close this mutex when this function exits.
- nsAutoHandle autoMutex(gHandlerMutex);
- // No need to initialize gHandlerReturnData.activitiesPerformed, since it
- // will be set by the handler. But we do need to initialize
- // gHandlerReturnData.handlerDataHasBeenSet so the handler knows that no
- // data has been set yet.
- gHandlerReturnData.handlerDataHasBeenSet = false;
- success = ReleaseMutex(gHandlerMutex);
- if (!success) {
- LOG_ERROR_MESSAGE(L"Unable to release mutex ownership: %#X",
- GetLastError());
- }
-
- // Finally ready to assemble the notification and dispatch it.
- WinToastTemplate toastTemplate =
- WinToastTemplate(WinToastTemplate::ImageAndText02);
- toastTemplate.setTextField(toastStrings->text1.get(),
- WinToastTemplate::FirstLine);
- toastTemplate.setTextField(toastStrings->text2.get(),
- WinToastTemplate::SecondLine);
- toastTemplate.addAction(toastStrings->action1.get());
- toastTemplate.addAction(toastStrings->action2.get());
- toastTemplate.setImagePath(absImagePath.get());
- toastTemplate.setScenario(WinToastTemplate::Scenario::Reminder);
- ToastHandler* handler =
- new ToastHandler(whichNotification, event.get(), aumi);
- INT64 id = WinToast::instance()->showToast(toastTemplate, handler, &error);
- if (id < 0) {
- LOG_ERROR_MESSAGE(WinToast::strerror(error).c_str());
- return;
- }
-
- DWORD result =
- WaitForSingleObject(event.get(), NOTIFICATION_WAIT_TIMEOUT_MS);
- // Don't return after these errors. Attempt to hide the notification.
- if (result == WAIT_FAILED) {
- LOG_ERROR_MESSAGE(L"Unable to wait on event object: %#X", GetLastError());
- } else if (result == WAIT_TIMEOUT) {
- LOG_ERROR_MESSAGE(L"Timed out waiting for event object");
- } else {
- result = WaitForSingleObject(gHandlerMutex, MUTEX_TIMEOUT_MS);
- if (result == WAIT_TIMEOUT) {
- LOG_ERROR_MESSAGE(L"Unable to obtain mutex ownership");
- // activitiesPerformed is already set to error. No change needed.
- } else if (result == WAIT_FAILED) {
- LOG_ERROR_MESSAGE(L"Failed to wait on mutex: %#X", GetLastError());
- // activitiesPerformed is already set to error. No change needed.
- } else if (result == WAIT_ABANDONED) {
- LOG_ERROR_MESSAGE(L"Found abandoned mutex");
- ReleaseMutex(gHandlerMutex);
- // activitiesPerformed is already set to error. No change needed.
- } else {
- // Mutex is being held. It is safe to access gHandlerReturnData.
- // If gHandlerReturnData.handlerDataHasBeenSet is false, the handler
- // never ran. Use the error value activitiesPerformed already contains.
- if (gHandlerReturnData.handlerDataHasBeenSet) {
- activitiesPerformed = gHandlerReturnData.activitiesPerformed;
- }
-
- success = ReleaseMutex(gHandlerMutex);
- if (!success) {
- LOG_ERROR_MESSAGE(L"Unable to release mutex ownership: %#X",
- GetLastError());
- }
- }
- }
-
- if (!WinToast::instance()->hideToast(id)) {
- LOG_ERROR_MESSAGE(L"Failed to hide notification");
- }
- });
- return activitiesPerformed;
-}
-
-// Previously this function checked that the Firefox build was using English.
-// This was checked because of the peculiar way we were localizing toast
-// notifications where we used a completely different set of strings in English.
-//
-// We've since unified the notification flows but need to clean up unused code
-// and config files - Bug 1826375.
-bool FirefoxInstallIsEnglish() { return false; }
-
-// If a notification is shown, this function will block until the notification
-// is activated or dismissed.
-// aumi is the App User Model ID.
-NotificationActivities MaybeShowNotification(
- const DefaultBrowserInfo& browserInfo, const wchar_t* aumi, bool force) {
- // Default to not showing a notification. Any other value will be returned
- // directly from ShowNotification.
- NotificationActivities activitiesPerformed = {NotificationType::Initial,
- NotificationShown::NotShown,
- NotificationAction::NoAction};
-
- // Reset notification state machine, user setting default browser to Firefox
- // is a strong signal that they intend to have it as the default browser.
- if (browserInfo.currentDefaultBrowser == Browser::Firefox) {
- ResetInitialNotificationShown();
- }
-
- bool initialNotificationShown = GetInitialNotificationShown();
- if (!initialNotificationShown || force) {
- if ((browserInfo.currentDefaultBrowser == Browser::EdgeWithBlink &&
- browserInfo.previousDefaultBrowser == Browser::Firefox) ||
- force) {
- return ShowNotification(NotificationType::Initial, aumi);
- }
- return activitiesPerformed;
- }
- activitiesPerformed.type = NotificationType::Followup;
-
- ULONGLONG followupNotificationRequestTime =
- GetFollowupNotificationRequestTime();
- bool followupNotificationRequested = followupNotificationRequestTime != 0;
- bool followupNotificationShown = GetFollowupNotificationShown();
- if (followupNotificationRequested && !followupNotificationShown &&
- !GetFollowupNotificationSuppressed()) {
- ULONGLONG secondsSinceRequestTime =
- SecondsPassedSince(followupNotificationRequestTime);
-
- if (secondsSinceRequestTime >= SEVEN_DAYS_IN_SECONDS) {
- // If we go to show the followup notification and the user has already
- // changed the default browser, permanently suppress the followup since
- // it's no longer relevant.
- if (browserInfo.currentDefaultBrowser == Browser::EdgeWithBlink) {
- return ShowNotification(NotificationType::Followup, aumi);
- } else {
- SetFollowupNotificationSuppressed(true);
- }
- }
- }
- return activitiesPerformed;
-}
-
std::string GetStringForNotificationType(NotificationType type) {
switch (type) {
case NotificationType::Initial: