// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_SAFETY_CHECK_NOTIFICATIONS_MODEL_SAFETY_CHECK_NOTIFICATION_CLIENT_H_
#define IOS_CHROME_BROWSER_SAFETY_CHECK_NOTIFICATIONS_MODEL_SAFETY_CHECK_NOTIFICATION_CLIENT_H_
#import <Foundation/Foundation.h>
#import <UserNotifications/UserNotifications.h>
#import "base/functional/callback_forward.h"
#import "base/memory/scoped_refptr.h"
#import "base/memory/weak_ptr.h"
#import "base/sequence_checker.h"
#import "base/task/sequenced_task_runner.h"
#import "ios/chrome/browser/passwords/model/password_checkup_utils.h"
#import "ios/chrome/browser/push_notification/model/push_notification_client.h"
#import "ios/chrome/browser/safety_check/model/ios_chrome_safety_check_manager.h"
#import "ios/chrome/browser/safety_check/model/ios_chrome_safety_check_manager_constants.h"
// A push notification client for managing Safety Check-related notifications.
// Observes Safety Check state changes to ensure notifications are accurate, and
// handles user registration, notification delivery, and user interaction.
class SafetyCheckNotificationClient
: public PushNotificationClient,
public IOSChromeSafetyCheckManagerObserver {
public:
explicit SafetyCheckNotificationClient(
const scoped_refptr<base::SequencedTaskRunner> task_runner);
~SafetyCheckNotificationClient() override;
// `PushNotificationClient` overrides.
void HandleNotificationInteraction(
UNNotificationResponse* notification_response) override;
UIBackgroundFetchResult HandleNotificationReception(
NSDictionary<NSString*, id>* notification) override;
NSArray<UNNotificationCategory*>* RegisterActionableNotifications() override;
void OnSceneActiveForegroundBrowserReady() override;
// Called when the scene becomes "active foreground" and the browser is
// ready. `completion` will be called when all async operations are done.
void OnSceneActiveForegroundBrowserReady(base::OnceClosure completion);
// `IOSChromeSafetyCheckManagerObserver` overrides.
void PasswordCheckStateChanged(PasswordSafetyCheckState state,
password_manager::InsecurePasswordCounts
insecure_password_counts) override;
void SafeBrowsingCheckStateChanged(
SafeBrowsingSafetyCheckState state) override;
void UpdateChromeCheckStateChanged(
UpdateChromeSafetyCheckState state) override;
void RunningStateChanged(RunningSafetyCheckState state) override;
void ManagerWillShutdown(
IOSChromeSafetyCheckManager* safety_check_manager) override;
private:
// Callback type used with `GetPendingRequests()`.
using GetPendingRequestsCallback =
base::OnceCallback<void(NSArray<UNNotificationRequest*>*)>;
// Calls `completion` with all pending requests matching `identifiers`.
void GetPendingRequests(NSArray<NSString*>* identifiers,
GetPendingRequestsCallback completion);
// Returns true if the user has enabled Safety Check notifications, either in
// the Notifications Settings UI or through an opt-in prompt (e.g., Magic
// Stack, Safety Check page, Password Checkup page).
bool IsPermitted();
// Called when notifications matching `identifiers` are cleared from the
// pending notification requests schedule.
void OnNotificationsCleared(NSArray<NSString*>* identifiers,
NSArray<UNNotificationRequest*>* requests);
// Clears any previously scheduled notifications matching `identifiers`. Runs
// `completion` at the end, once all async operations have completed.
void ClearNotifications(NSArray<NSString*>* identifiers,
base::OnceClosure completion);
// Schedules new Safety Check notifications reflecting `update_chrome_state`,
// `safe_browsing_state`, and `password_state`/`insecure_password_counts`, if
// permitted. Runs `completion` at the end, once all async operations have
// completed.
void ScheduleSafetyCheckNotifications(
UpdateChromeSafetyCheckState update_chrome_state,
SafeBrowsingSafetyCheckState safe_browsing_state,
PasswordSafetyCheckState password_state,
password_manager::InsecurePasswordCounts insecure_password_counts,
base::OnceClosure completion);
// Clears any existing Safety Check notifications and schedules new ones
// reflecting the latest `update_chrome_state`, `safe_browsing_state`, and
// `password_state`/`insecure_password_counts`, if permitted. Runs
// `completion` at the end, once all async operations have completed.
void ClearAndRescheduleSafetyCheckNotifications(
UpdateChromeSafetyCheckState update_chrome_state,
SafeBrowsingSafetyCheckState safe_browsing_state,
PasswordSafetyCheckState password_state,
password_manager::InsecurePasswordCounts insecure_password_counts,
base::OnceClosure completion);
// Current state of the Update Chrome check.
UpdateChromeSafetyCheckState update_chrome_check_state_ =
UpdateChromeSafetyCheckState::kDefault;
// Current state of the Password check.
PasswordSafetyCheckState password_check_state_ =
PasswordSafetyCheckState::kDefault;
// Current state of the Safe Browsing check.
SafeBrowsingSafetyCheckState safe_browsing_check_state_ =
SafeBrowsingSafetyCheckState::kDefault;
// The count of passwords flagged as compromised, dismissed, reused, and weak
// by the Safety Check.
password_manager::InsecurePasswordCounts insecure_password_counts_ = {
/* compromised */ 0, /* dismissed */ 0, /* reused */ 0,
/* weak */ 0};
// Validates asynchronous `PushNotificationClient` events are evaluated on the
// same sequence that `SafetyCheckNotificationClient` was created on.
SEQUENCE_CHECKER(sequence_checker_);
// Ensures `IOSChromeSafetyCheckManagerObserver` events are posted on the
// same sequence that `SafetyCheckNotificationClient` was created on.
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::WeakPtrFactory<SafetyCheckNotificationClient> weak_ptr_factory_{this};
};
#endif // IOS_CHROME_BROWSER_SAFETY_CHECK_NOTIFICATIONS_MODEL_SAFETY_CHECK_NOTIFICATION_CLIENT_H_