910e62b5创建于 1月15日历史提交
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_SAFETY_HUB_MENU_NOTIFICATION_SERVICE_H_
#define CHROME_BROWSER_UI_SAFETY_HUB_MENU_NOTIFICATION_SERVICE_H_

#include <list>
#include <map>
#include <memory>
#include <optional>

#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/ui/safety_hub/menu_notification.h"
#include "chrome/browser/ui/safety_hub/notification_permission_review_service.h"
#include "chrome/browser/ui/safety_hub/revoked_permissions_service.h"
#include "chrome/browser/ui/safety_hub/safety_hub_constants.h"
#include "chrome/browser/ui/safety_hub/safety_hub_result.h"
#include "components/keyed_service/core/keyed_service.h"

#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/extensions/cws_info_service.h"
#include "chrome/browser/ui/safety_hub/password_status_check_service.h"
#endif  // BUILDFLAG(IS_ANDROID)

struct MenuNotificationEntry {
  int command = 0;
  std::u16string label;
  safety_hub::SafetyHubModuleType module;
};

namespace {

enum MenuNotificationPriority {
  LOW = 0,
  MEDIUM,
  HIGH,
};

struct SafetyHubModuleInfoElement {
  SafetyHubModuleInfoElement();
  ~SafetyHubModuleInfoElement();
  SafetyHubModuleInfoElement(
      MenuNotificationPriority priority,
      base::TimeDelta interval,
      base::RepeatingCallback<std::optional<std::unique_ptr<SafetyHubResult>>()>
          result_getter,
      std::unique_ptr<SafetyHubMenuNotification> notification);

  MenuNotificationPriority priority;
  base::TimeDelta interval;
  base::RepeatingCallback<std::optional<std::unique_ptr<SafetyHubResult>>()>
      result_getter;
  std::unique_ptr<SafetyHubMenuNotification> notification;
};

using ResultMap =
    std::map<safety_hub::SafetyHubModuleType, std::unique_ptr<SafetyHubResult>>;

}  // namespace

// This class manages the notifications that should be shown when a user opens
// the three-dot menu. It will collect the latest results from all the Safety
// Hub service and subsequently update the notifications. Based on priority and
// prior showing of notification, it will determine which notification that
// should be shown.
class SafetyHubMenuNotificationService : public KeyedService {
 public:
  explicit SafetyHubMenuNotificationService(
      PrefService* pref_service,
      RevokedPermissionsService* revoked_permissions_service,
      NotificationPermissionsReviewService* notification_permissions_service,
#if !BUILDFLAG(IS_ANDROID)
      PasswordStatusCheckService* password_check_service,
#endif  // BUILDFLAG(IS_ANDROID)
      Profile* profile);
  SafetyHubMenuNotificationService(const SafetyHubMenuNotificationService&) =
      delete;
  SafetyHubMenuNotificationService& operator=(
      const SafetyHubMenuNotificationService&) = delete;

  ~SafetyHubMenuNotificationService() override;

  // Returns the CommandID and notification string that should be shown in the
  // three-dot menu. When no notification should be shown, std::nullopt will be
  // returned.
  std::optional<MenuNotificationEntry> GetNotificationToShow();

  // Dismisses all the active menu notifications.
  void DismissActiveNotification();

  // Dismisses the active menu notification of the specified module.
  void DismissActiveNotificationOfModule(
      safety_hub::SafetyHubModuleType module);

  void UpdateResultGetterForTesting(
      safety_hub::SafetyHubModuleType type,
      base::RepeatingCallback<std::optional<std::unique_ptr<SafetyHubResult>>()>
          result_getter);

 private:
  // Gets the latest result from each Safety Hub service. Will return
  // std::nullopt when there is no result from one of the services.
  std::optional<ResultMap> GetResultsFromAllModules();

  // Stores the notifications (which should have their results updated) as a
  // dict in the prefs.
  void SaveNotificationsToPrefs() const;

  // Creates a notification from the provided dictionary, for the specified
  // Safety Hub service type.
  std::unique_ptr<SafetyHubMenuNotification> GetNotificationFromDict(
      const base::Value::Dict& dict,
      safety_hub::SafetyHubModuleType& type) const;

  // Sets the relevant, static meta information for the three-dot menu
  // (priority, interval, and method to retrieve the relevant result) for a
  // specific type of Safety Hub module provided the dictionary that stores the
  // notifications.
  void SetInfoElement(
      safety_hub::SafetyHubModuleType type,
      MenuNotificationPriority priority,
      base::TimeDelta interval,
      base::RepeatingCallback<std::optional<std::unique_ptr<SafetyHubResult>>()>
          result_getter,
      const base::Value::Dict& stored_notifications);

  // Called when the pref for Safe Browsing has been updated.
  void OnSafeBrowsingPrefUpdate();

  // Returns if any safety hub notification has been shown in the menu so far.
  bool HasAnyNotificationBeenShown() const;

  // Holds the mapping from module type to pref name.
  std::map<safety_hub::SafetyHubModuleType, const char*> pref_dict_key_map_;

  // Preference service that persists the notifications.
  raw_ptr<PrefService> pref_service_;

  // A map that captures the meta information about menu notifications for each
  // Safety Hub module.
  std::map<safety_hub::SafetyHubModuleType,
           std::unique_ptr<SafetyHubModuleInfoElement>>
      module_info_map_;

  // Registrar to record the pref changes to Safe Browsing.
  PrefChangeRegistrar registrar_;
};

#endif  // CHROME_BROWSER_UI_SAFETY_HUB_MENU_NOTIFICATION_SERVICE_H_