diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index cccd6bc080f..35de9d0253e 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -303,7 +303,10 @@ import { BackgroundMemoryStorageService } from "../platform/storage/background-m import { BrowserStorageServiceProvider } from "../platform/storage/browser-storage-service.provider"; import { OffscreenStorageService } from "../platform/storage/offscreen-storage.service"; import { SyncServiceListener } from "../platform/sync/sync-service.listener"; -import { BrowserSystemNotificationService } from "../platform/system-notifications/browser-system-notification.service"; +import { + BrowserSystemNotificationService, + isNotificationsSupported, +} from "../platform/system-notifications/browser-system-notification.service"; import { fromChromeRuntimeMessaging } from "../platform/utils/from-chrome-runtime-messaging"; import { AtRiskCipherBadgeUpdaterService } from "../vault/services/at-risk-cipher-badge-updater.service"; @@ -1124,7 +1127,7 @@ export default class MainBackground { this.actionsService = new BrowserActionsService(this.logService, this.platformUtilsService); - if ("notifications" in chrome) { + if (isNotificationsSupported()) { this.systemNotificationService = new BrowserSystemNotificationService( this.platformUtilsService, ); diff --git a/apps/browser/src/platform/system-notifications/browser-system-notification.service.ts b/apps/browser/src/platform/system-notifications/browser-system-notification.service.ts index e0b2716a19b..0eb4739ea92 100644 --- a/apps/browser/src/platform/system-notifications/browser-system-notification.service.ts +++ b/apps/browser/src/platform/system-notifications/browser-system-notification.service.ts @@ -12,6 +12,16 @@ import { import { fromChromeEvent } from "../browser/from-chrome-event"; +/** + * A check to see if the current browser has the needed API to support the `BrowserSystemNotificationService`. + * + * This check should only be called during dependency creation, if consumers need to know if + * system notifications can be used they should use {@link SystemNotificationsService.isSupported}. + */ +export function isNotificationsSupported() { + return "notifications" in chrome && chrome.notifications != null; +} + export class BrowserSystemNotificationService implements SystemNotificationsService { notificationClicked$: Observable; diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index d68e71f3bc8..ab9dafc531a 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -112,6 +112,7 @@ import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/stora import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service"; import { SyncService } from "@bitwarden/common/platform/sync"; import { SystemNotificationsService } from "@bitwarden/common/platform/system-notifications/system-notifications.service"; +import { UnsupportedSystemNotificationsService } from "@bitwarden/common/platform/system-notifications/unsupported-system-notifications.service"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -183,7 +184,10 @@ import { ForegroundTaskSchedulerService } from "../../platform/services/task-sch import { BrowserStorageServiceProvider } from "../../platform/storage/browser-storage-service.provider"; import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service"; import { ForegroundSyncService } from "../../platform/sync/foreground-sync.service"; -import { BrowserSystemNotificationService } from "../../platform/system-notifications/browser-system-notification.service"; +import { + BrowserSystemNotificationService, + isNotificationsSupported, +} from "../../platform/system-notifications/browser-system-notification.service"; import { fromChromeRuntimeMessaging } from "../../platform/utils/from-chrome-runtime-messaging"; import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service"; import { Fido2UserVerificationService } from "../../vault/services/fido2-user-verification.service"; @@ -581,7 +585,13 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: SystemNotificationsService, - useClass: BrowserSystemNotificationService, + useFactory: (platformUtilsService: PlatformUtilsService) => { + if (isNotificationsSupported()) { + return new BrowserSystemNotificationService(platformUtilsService); + } + + return new UnsupportedSystemNotificationsService(); + }, deps: [PlatformUtilsService], }), safeProvider({ @@ -613,11 +623,6 @@ const safeProviders: SafeProvider[] = [ useClass: SsoUrlService, deps: [], }), - safeProvider({ - provide: SystemNotificationsService, - useClass: BrowserSystemNotificationService, - deps: [PlatformUtilsService], - }), safeProvider({ provide: LoginComponentService, useClass: ExtensionLoginComponentService, diff --git a/libs/common/src/platform/system-notifications/system-notifications.service.ts b/libs/common/src/platform/system-notifications/system-notifications.service.ts index f36e7da96ad..275b07342c2 100644 --- a/libs/common/src/platform/system-notifications/system-notifications.service.ts +++ b/libs/common/src/platform/system-notifications/system-notifications.service.ts @@ -35,6 +35,12 @@ export type SystemNotificationEvent = { * A service responsible for displaying operating system level server notifications. */ export abstract class SystemNotificationsService { + /** + * Used to know if a given platform supports system notifications. This check should + * be used to guard any usage of the other members in this service. + */ + abstract isSupported(): boolean; + abstract notificationClicked$: Observable; /** @@ -50,9 +56,4 @@ export abstract class SystemNotificationsService { * @param clearInfo Any info needed required to clear a notification. */ abstract clear(clearInfo: SystemNotificationClearInfo): Promise; - - /** - * Used to know if a given platform supports server notifications. - */ - abstract isSupported(): boolean; }