chromium/chromeos/ash/services/multidevice_setup/feature_state_manager_impl.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMEOS_ASH_SERVICES_MULTIDEVICE_SETUP_FEATURE_STATE_MANAGER_IMPL_H_
#define CHROMEOS_ASH_SERVICES_MULTIDEVICE_SETUP_FEATURE_STATE_MANAGER_IMPL_H_

#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/timer/timer.h"
#include "chromeos/ash/services/device_sync/public/cpp/device_sync_client.h"
#include "chromeos/ash/services/multidevice_setup/feature_state_manager.h"
#include "chromeos/ash/services/multidevice_setup/global_state_feature_manager.h"
#include "chromeos/ash/services/multidevice_setup/host_status_provider.h"
#include "chromeos/ash/services/multidevice_setup/public/cpp/android_sms_pairing_state_tracker.h"
#include "chromeos/ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "components/prefs/pref_change_registrar.h"

class PrefService;

namespace ash {

namespace multidevice_setup {

// Concrete FeatureStateManager implementation. This class relies on
// HostStatusProvider and DeviceSyncClient to determine if features are
// available at all (features are not available unless a verified host is set
// which has enabled the features). To track enabled/disabled/policy state, this
// class utilizes per-user preferences.
class FeatureStateManagerImpl : public FeatureStateManager,
                                public HostStatusProvider::Observer,
                                public device_sync::DeviceSyncClient::Observer,
                                public AndroidSmsPairingStateTracker::Observer {
 public:
  class Factory {
   public:
    static std::unique_ptr<FeatureStateManager> Create(
        PrefService* pref_service,
        HostStatusProvider* host_status_provider,
        device_sync::DeviceSyncClient* device_sync_client,
        AndroidSmsPairingStateTracker* android_sms_pairing_state_tracker,
        const base::flat_map<mojom::Feature, GlobalStateFeatureManager*>&
            global_state_feature_managers,
        bool is_secondary_user);
    static void SetFactoryForTesting(Factory* test_factory);

   protected:
    virtual ~Factory();
    virtual std::unique_ptr<FeatureStateManager> CreateInstance(
        PrefService* pref_service,
        HostStatusProvider* host_status_provider,
        device_sync::DeviceSyncClient* device_sync_client,
        AndroidSmsPairingStateTracker* android_sms_pairing_state_tracker,
        const base::flat_map<mojom::Feature, GlobalStateFeatureManager*>&
            global_state_feature_managers,
        bool is_secondary_user) = 0;

   private:
    static Factory* test_factory_;
  };

  FeatureStateManagerImpl(const FeatureStateManagerImpl&) = delete;
  FeatureStateManagerImpl& operator=(const FeatureStateManagerImpl&) = delete;

  ~FeatureStateManagerImpl() override;

 private:
  FeatureStateManagerImpl(
      PrefService* pref_service,
      HostStatusProvider* host_status_provider,
      device_sync::DeviceSyncClient* device_sync_client,
      AndroidSmsPairingStateTracker* android_sms_pairing_state_tracker,
      const base::flat_map<mojom::Feature, GlobalStateFeatureManager*>&
          global_state_feature_managers,
      bool is_secondary_user);

  // FeatureStateManager:
  FeatureStatesMap GetFeatureStates() override;
  void PerformSetFeatureEnabledState(mojom::Feature feature,
                                     bool enabled) override;

  // HostStatusProvider::Observer,
  void OnHostStatusChange(const HostStatusProvider::HostStatusWithDevice&
                              host_status_with_device) override;

  // DeviceSyncClient::Observer:
  void OnNewDevicesSynced() override;

  // AndroidSmsPairingStateTracker::Observer:
  void OnPairingStateChanged() override;

  void OnPrefValueChanged();
  void UpdateFeatureStateCache(bool notify_observers_of_changes);
  mojom::FeatureState ComputeFeatureState(mojom::Feature feature);
  bool IsAllowedByPolicy(mojom::Feature feature);
  bool IsSupportedByChromebook(mojom::Feature feature);
  bool HasSufficientSecurity(mojom::Feature feature,
                             const multidevice::RemoteDeviceRef& host_device);
  bool HasBeenActivatedByPhone(mojom::Feature feature,
                               const multidevice::RemoteDeviceRef& host_device);
  bool RequiresFurtherSetup(mojom::Feature feature);
  mojom::FeatureState GetEnabledOrDisabledState(mojom::Feature feature);

  // Log the feature states in |cached_feature_state_map_|. Called 1) on
  // sign-in, 2) when at least one feature state changes, and 3) every 30
  // minutes. The latter is necessary to capture users who stay logged in longer
  // than UMA aggregation periods and don't change feature state.
  void LogFeatureStates() const;

  raw_ptr<PrefService> pref_service_;
  raw_ptr<HostStatusProvider> host_status_provider_;
  raw_ptr<device_sync::DeviceSyncClient> device_sync_client_;
  raw_ptr<AndroidSmsPairingStateTracker> android_sms_pairing_state_tracker_;
  const base::flat_map<mojom::Feature, GlobalStateFeatureManager*>
      global_state_feature_managers_;

  // Certain features may be unavailable to secondary users logged into a
  // Chromebook. Currently, such features include PhoneHub and its subfeatures.
  const bool is_secondary_user_;

  // Map from feature to the pref name which indicates the enabled/disabled
  // boolean state for the feature.
  base::flat_map<mojom::Feature, std::string> feature_to_enabled_pref_name_map_;

  // Same as above, except that the pref names represent whether the feature is
  // allowed by policy or not.
  base::flat_map<mojom::Feature, std::string> feature_to_allowed_pref_name_map_;

  // Map from feature to state, which is updated each time a feature's state
  // changes. This cache is used to determine when a feature's state has changed
  // so that observers can be notified.
  FeatureStatesMap cached_feature_state_map_;

  base::RepeatingTimer feature_state_metric_timer_;

  PrefChangeRegistrar registrar_;
};

}  // namespace multidevice_setup

}  // namespace ash

#endif  // CHROMEOS_ASH_SERVICES_MULTIDEVICE_SETUP_FEATURE_STATE_MANAGER_IMPL_H_