chromium/chrome/browser/chromeos/extensions/wm/wm_desks_private_events.cc

// 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.

#include "chrome/browser/chromeos/extensions/wm/wm_desks_private_events.h"

#include "base/check_is_test.h"
#include "base/lazy_instance.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/wm_desks_private.h"
#include "chromeos/lacros/lacros_service.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/event_router_factory.h"
#include "extensions/browser/extension_event_histogram_value.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_registry_factory.h"
#include "extensions/browser/extension_system.h"

namespace extensions {

WMDesksEventsRouter::WMDesksEventsRouter(Profile* profile)
    : event_router_(EventRouter::Get(profile)) {}

WMDesksEventsRouter::~WMDesksEventsRouter() = default;

void WMDesksEventsRouter::OnDeskAdded(const base::Uuid& desk_id,
                                      bool from_undo) {
  if (!event_router_) {
    CHECK_IS_TEST();
    return;
  }

  auto event = std::make_unique<Event>(
      from_undo ? events::DESK_EVENTS_ON_DESK_REMOVAL_UNDONE
                : events::DESK_EVENTS_ON_DESK_ADDED,
      api::wm_desks_private::OnDeskAdded::kEventName,
      base::Value::List()
          .Append(desk_id.AsLowercaseString())
          .Append(from_undo));
  event_router_->BroadcastEvent(std::move(event));
}

void WMDesksEventsRouter::OnDeskRemoved(const base::Uuid& desk_id) {
  if (!event_router_) {
    CHECK_IS_TEST();
    return;
  }

  auto event = std::make_unique<Event>(
      events::DESK_EVENTS_ON_DESK_REMOVED,
      api::wm_desks_private::OnDeskRemoved::kEventName,
      base::Value::List().Append(desk_id.AsLowercaseString()));
  event_router_->BroadcastEvent(std::move(event));
}

void WMDesksEventsRouter::OnDeskSwitched(const base::Uuid& deactivated,
                                         const base::Uuid& activated) {
  if (!event_router_) {
    CHECK_IS_TEST();
    return;
  }

  auto event =
      std::make_unique<Event>(events::DESK_EVENTS_ON_DESK_SWITCHED,
                              api::wm_desks_private::OnDeskSwitched::kEventName,
                              base::Value::List()
                                  .Append(deactivated.AsLowercaseString())
                                  .Append(activated.AsLowercaseString()));
  event_router_->BroadcastEvent(std::move(event));
}

WMDesksPrivateEventsAPI::WMDesksPrivateEventsAPI(
    content::BrowserContext* context)
    : profile_(Profile::FromBrowserContext(context)) {
  // Register for listener added and removed events.
  auto* router = EventRouter::Get(profile_);
  router->RegisterObserver(this,
                           api::wm_desks_private::OnDeskAdded::kEventName);
  router->RegisterObserver(this,
                           api::wm_desks_private::OnDeskRemoved::kEventName);
  router->RegisterObserver(this,
                           api::wm_desks_private::OnDeskSwitched::kEventName);
}

WMDesksPrivateEventsAPI::~WMDesksPrivateEventsAPI() = default;

// static
BrowserContextKeyedAPIFactory<WMDesksPrivateEventsAPI>*
WMDesksPrivateEventsAPI::GetFactoryInstance() {
  static base::NoDestructor<
      BrowserContextKeyedAPIFactory<WMDesksPrivateEventsAPI>>
      instance;
  return instance.get();
}

WMDesksPrivateEventsAPI* WMDesksPrivateEventsAPI::Get(
    content::BrowserContext* context) {
  return GetFactoryInstance()->Get(context);
}

void WMDesksPrivateEventsAPI::Shutdown() {
  if (auto* router = EventRouter::Get(profile_)) {
    router->UnregisterObserver(this);
  }
}

void WMDesksPrivateEventsAPI::OnListenerAdded(
    const EventListenerInfo& details) {
  if (!desk_events_router_ && HasDeskEventsListener()) {
    desk_events_router_ = std::make_unique<WMDesksEventsRouter>(profile_);
#if BUILDFLAG(IS_CHROMEOS_LACROS)
    // Only register once
    chromeos::LacrosService* service = chromeos::LacrosService::Get();
    if (!service->IsAvailable<crosapi::mojom::Desk>() ||
        service->GetInterfaceVersion<crosapi::mojom::Desk>() <
            static_cast<int>(crosapi::mojom::Desk::MethodMinVersions::
                                 kAddDeskEventObserverMinVersion)) {
      return;
    }
    service->GetRemote<crosapi::mojom::Desk>()->AddDeskEventObserver(
        desk_events_router_->BindDeskClient());
#endif
  }
}

void WMDesksPrivateEventsAPI::OnListenerRemoved(
    const EventListenerInfo& details) {
  if (!HasDeskEventsListener()) {
    desk_events_router_.reset();
  }
}

bool WMDesksPrivateEventsAPI::HasDeskEventsListener() {
  auto* router = EventRouter::Get(profile_);
  return router->HasEventListener(
             api::wm_desks_private::OnDeskAdded::kEventName) ||
         router->HasEventListener(
             api::wm_desks_private::OnDeskRemoved::kEventName) ||
         router->HasEventListener(
             api::wm_desks_private::OnDeskSwitched::kEventName);
}

}  // namespace extensions