chromium/chrome/browser/android/search_permissions/search_permissions_service.h

// Copyright 2017 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_ANDROID_SEARCH_PERMISSIONS_SEARCH_PERMISSIONS_SERVICE_H_
#define CHROME_BROWSER_ANDROID_SEARCH_PERMISSIONS_SEARCH_PERMISSIONS_SERVICE_H_

#include <string>

#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/singleton.h"
#include "chrome/browser/profiles/profile_keyed_service_factory.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/keyed_service/core/keyed_service.h"
#include "url/origin.h"

namespace content {
class BrowserContext;
}

namespace user_prefs {
class PrefRegistrySyncable;
}

class HostContentSettingsMap;
class PrefService;
class Profile;

// NOTE(crbug/1230193): The DSE auto-granted permissions have been disabled and
// all of the previously granted permissions are reverted in the initialization
// step.
// Helper class to manage DSE permissions. It keeps the setting valid by
// watching change to the CCTLD and DSE.
// Glossary:
//     DSE: Default Search Engine
//     CCTLD: Country Code Top Level Domain (e.g. google.com.au)
class SearchPermissionsService : public KeyedService {
 public:
  // Delegate for search engine related functionality. Can be overridden for
  // testing.
  class SearchEngineDelegate {
   public:
    virtual ~SearchEngineDelegate() {}

    // Returns the name of the current DSE.
    virtual std::u16string GetDSEName() = 0;

    // Returns the origin of the DSE. If the current DSE is Google this will
    // return the current CCTLD.
    virtual url::Origin GetDSEOrigin() = 0;
  };

  // Factory implementation will not create a service in incognito.
  class Factory : public ProfileKeyedServiceFactory {
   public:
    static SearchPermissionsService* GetForBrowserContext(
        content::BrowserContext* context);

    static Factory* GetInstance();

   private:
    friend struct base::DefaultSingletonTraits<Factory>;

    Factory();
    ~Factory() override;

    // BrowserContextKeyedServiceFactory
    bool ServiceIsCreatedWithBrowserContext() const override;
    KeyedService* BuildServiceInstanceFor(
        content::BrowserContext* profile) const override;
    void RegisterProfilePrefs(
        user_prefs::PrefRegistrySyncable* registry) override;
  };

  explicit SearchPermissionsService(Profile* profile);

  // Returns whether the given origin matches the DSE origin.
  bool IsDseOrigin(const url::Origin& origin);

  // KeyedService:
  void Shutdown() override;

 private:
  friend class ChromeBrowsingDataRemoverDelegateTest;
  friend class SearchPermissionsServiceTest;
  FRIEND_TEST_ALL_PREFIXES(GeolocationPermissionContextDelegateTests,
                           SearchGeolocationInIncognito);
  struct PrefValue;

  ~SearchPermissionsService() override;

  // Restore the setting for an origin before it became the DSE. Returns the
  // setting that the origin was set to before restoring the old value.
  ContentSetting RestoreOldSettingAndReturnPrevious(
      const GURL& dse_origin,
      ContentSettingsType type,
      ContentSetting setting_to_restore,
      bool preserve_block_setting);

  // Initialize the DSE permission settings if they haven't already been
  // initialized. Also, if they haven't been initialized, reset whether the DSE
  // geolocation disclosure has been shown to ensure user who may have seen it
  // on earlier versions (due to Finch experiments) see it again.
  void InitializeSettingsIfNeeded();

  PrefValue GetDSEPref();

  // Retrieve the content setting for the given permission/origin.
  ContentSetting GetContentSetting(const GURL& origin,
                                   ContentSettingsType type);
  // Set the content setting for the given permission/origin.
  void SetContentSetting(const GURL& origin,
                         ContentSettingsType type,
                         ContentSetting setting);

  // Record how the content setting transitions when DSE permissions autogrant
  // is disabled via feature.
  void RecordAutoDSEPermissionReverted(ContentSettingsType permission_type,
                                       ContentSetting backed_up_setting,
                                       ContentSetting effective_setting,
                                       const GURL& origin);

  // Record the content settings for notifications and geolocation on the DSE
  // origin. Called at initialization or when the DSE origin changes.
  void RecordEffectiveDSEOriginPermissions();

  void SetSearchEngineDelegateForTest(
      std::unique_ptr<SearchEngineDelegate> delegate);

  // Simulate an existing `prefs::kDSEPermissionsSettings` entry with the
  // provided settings. Used to test automatically reverting the pre-granted DSE
  // permissions.
  void SetDSEPrefForTesting(ContentSetting geolocation_setting_to_restore,
                            ContentSetting notifications_setting_to_restore);

  raw_ptr<Profile> profile_;
  raw_ptr<PrefService> pref_service_;
  raw_ptr<HostContentSettingsMap> host_content_settings_map_;
  std::unique_ptr<SearchEngineDelegate> delegate_;
};

#endif  // CHROME_BROWSER_ANDROID_SEARCH_PERMISSIONS_SEARCH_PERMISSIONS_SERVICE_H_