chromium/chromeos/ash/services/multidevice_setup/wifi_sync_notification_controller.cc

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

#include "chromeos/ash/services/multidevice_setup/wifi_sync_notification_controller.h"

#include <memory>
#include <optional>

#include "base/memory/ptr_util.h"
#include "base/power_monitor/power_monitor.h"
#include "base/trace_event/trace_event.h"
#include "chromeos/ash/components/multidevice/logging/logging.h"
#include "chromeos/ash/components/multidevice/remote_device_ref.h"
#include "chromeos/ash/components/multidevice/software_feature.h"
#include "chromeos/ash/components/multidevice/software_feature_state.h"
#include "chromeos/ash/services/device_sync/public/cpp/device_sync_client.h"
#include "chromeos/ash/services/multidevice_setup/account_status_change_delegate_notifier.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/prefs.h"
#include "chromeos/ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"

namespace ash {

namespace multidevice_setup {

const char kCanShowWifiSyncAnnouncementPrefName[] =
    "multidevice_setup.can_show_wifi_sync_announcement";

// static
WifiSyncNotificationController::Factory*
    WifiSyncNotificationController::Factory::test_factory_ = nullptr;

// static
std::unique_ptr<WifiSyncNotificationController>
WifiSyncNotificationController::Factory::Create(
    GlobalStateFeatureManager* wifi_sync_feature_manager,
    HostStatusProvider* host_status_provider,
    PrefService* pref_service,
    device_sync::DeviceSyncClient* device_sync_client,
    AccountStatusChangeDelegateNotifier* delegate_notifier) {
  if (test_factory_) {
    return test_factory_->CreateInstance(wifi_sync_feature_manager,
                                         host_status_provider, pref_service,
                                         device_sync_client, delegate_notifier);
  }

  return base::WrapUnique(new WifiSyncNotificationController(
      wifi_sync_feature_manager, host_status_provider, pref_service,
      device_sync_client, delegate_notifier));
}

// static
void WifiSyncNotificationController::Factory::SetFactoryForTesting(
    Factory* test_factory) {
  test_factory_ = test_factory;
}

WifiSyncNotificationController::Factory::~Factory() = default;

void WifiSyncNotificationController::RegisterPrefs(
    PrefRegistrySimple* registry) {
  registry->RegisterBooleanPref(kCanShowWifiSyncAnnouncementPrefName, true);
}

WifiSyncNotificationController::WifiSyncNotificationController(
    GlobalStateFeatureManager* wifi_sync_feature_manager,
    HostStatusProvider* host_status_provider,
    PrefService* pref_service,
    device_sync::DeviceSyncClient* device_sync_client,
    AccountStatusChangeDelegateNotifier* delegate_notifier)
    : wifi_sync_feature_manager_(wifi_sync_feature_manager),
      host_status_provider_(host_status_provider),
      pref_service_(pref_service),
      device_sync_client_(device_sync_client),
      delegate_notifier_(delegate_notifier) {
  if (pref_service_->GetBoolean(kCanShowWifiSyncAnnouncementPrefName)) {
    session_manager::SessionManager::Get()->AddObserver(this);
    base::PowerMonitor::AddPowerSuspendObserver(this);
    did_register_session_observers_ = true;
  }
}

WifiSyncNotificationController::~WifiSyncNotificationController() {
  if (did_register_session_observers_) {
    session_manager::SessionManager::Get()->RemoveObserver(this);
    base::PowerMonitor::RemovePowerSuspendObserver(this);
  }
}

void WifiSyncNotificationController::OnSessionStateChanged() {
  TRACE_EVENT0("login",
               "WifiSyncNotificationController::OnSessionStateChanged");
  ShowAnnouncementNotificationIfEligible();
}

void WifiSyncNotificationController::OnResume() {
  ShowAnnouncementNotificationIfEligible();
}

void WifiSyncNotificationController::ShowAnnouncementNotificationIfEligible() {
  TRACE_EVENT0(
      "ui",
      "WifiSyncNotificationController::ShowAnnouncementNotificationIfEligible");
  // Show the announcement notification when the device is unlocked and
  // eligible for wi-fi sync.  This is done on unlock/resume to avoid showing
  // it on the first sign-in when it would distract from showoff and other
  // announcements.

  if (session_manager::SessionManager::Get()->IsUserSessionBlocked()) {
    return;
  }

  if (!IsFeatureAllowed(mojom::Feature::kWifiSync, pref_service_)) {
    return;
  }

  if (!pref_service_->GetBoolean(kCanShowWifiSyncAnnouncementPrefName)) {
    return;
  }

  if (!IsWifiSyncSupported()) {
    return;
  }

  if (host_status_provider_->GetHostWithStatus().host_status() !=
          mojom::HostStatus::kHostVerified ||
      wifi_sync_feature_manager_->IsFeatureEnabled()) {
    pref_service_->SetBoolean(kCanShowWifiSyncAnnouncementPrefName, false);
    return;
  }

  if (!delegate_notifier_->delegate()) {
    return;
  }

  delegate_notifier_->delegate()->OnBecameEligibleForWifiSync();
  pref_service_->SetBoolean(kCanShowWifiSyncAnnouncementPrefName, false);
}

bool WifiSyncNotificationController::IsWifiSyncSupported() {
  HostStatusProvider::HostStatusWithDevice host_with_status =
      host_status_provider_->GetHostWithStatus();
  if (host_with_status.host_status() != mojom::HostStatus::kHostVerified) {
    return false;
  }

  std::optional<multidevice::RemoteDeviceRef> host_device =
      host_with_status.host_device();
  if (!host_device) {
    PA_LOG(ERROR) << "WifiSyncNotificationController::" << __func__
                  << ": Host device unexpectedly null.";
    return false;
  }

  if (host_device->GetSoftwareFeatureState(
          multidevice::SoftwareFeature::kWifiSyncHost) ==
      multidevice::SoftwareFeatureState::kNotSupported) {
    return false;
  }

  std::optional<multidevice::RemoteDeviceRef> local_device =
      device_sync_client_->GetLocalDeviceMetadata();
  if (!local_device) {
    PA_LOG(ERROR) << "WifiSyncNotificationController::" << __func__
                  << ": Local device unexpectedly null.";
    return false;
  }

  if (local_device->GetSoftwareFeatureState(
          multidevice::SoftwareFeature::kWifiSyncClient) ==
      multidevice::SoftwareFeatureState::kNotSupported) {
    return false;
  }

  return true;
}

}  // namespace multidevice_setup

}  // namespace ash