chromium/chrome/browser/apps/app_service/instance_registry_updater.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 "chrome/browser/apps/app_service/instance_registry_updater.h"

#include "chrome/browser/ash/crosapi/browser_util.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "components/services/app_service/public/cpp/instance_registry.h"
#include "ui/aura/window.h"

namespace apps {

namespace {

static InstanceState GetState(bool visible, bool active) {
  auto state = static_cast<InstanceState>(InstanceState::kStarted |
                                          InstanceState::kRunning);
  if (visible) {
    state = static_cast<InstanceState>(state | InstanceState::kVisible);
  }
  if (active) {
    // If the app is active, it should be started, running, and visible.
    state = static_cast<InstanceState>(state | InstanceState::kVisible |
                                       InstanceState::kActive);
  }
  return state;
}

bool IsAshBrowserWindow(aura::Window* aura_window) {
  for (Browser* browser : *BrowserList::GetInstance()) {
    BrowserWindow* window = browser->window();
    if (window && window->GetNativeWindow() == aura_window) {
      return true;
    }
  }
  return false;
}

}  // namespace

InstanceRegistryUpdater::InstanceRegistryUpdater(
    BrowserAppInstanceRegistry& browser_app_instance_registry,
    InstanceRegistry& instance_registry)
    : browser_app_instance_registry_(browser_app_instance_registry),
      instance_registry_(instance_registry) {
  if (aura::Env::HasInstance()) {
    env_observer_.Observe(aura::Env::GetInstance());
  }
  browser_app_instance_registry_observation_.Observe(
      &*browser_app_instance_registry_);
}

InstanceRegistryUpdater::~InstanceRegistryUpdater() = default;

void InstanceRegistryUpdater::OnBrowserWindowAdded(
    const BrowserWindowInstance& instance) {
  OnBrowserWindowUpdated(instance);
}

void InstanceRegistryUpdater::OnBrowserWindowUpdated(
    const BrowserWindowInstance& instance) {
  InstanceState state =
      GetState(instance.window->IsVisible(), instance.is_active());
  OnInstance(instance.id, instance.GetAppId(), instance.window, state);
}

void InstanceRegistryUpdater::OnBrowserWindowRemoved(
    const BrowserWindowInstance& instance) {
  OnInstance(instance.id, instance.GetAppId(), instance.window,
             InstanceState::kDestroyed);
}

void InstanceRegistryUpdater::OnBrowserAppAdded(
    const BrowserAppInstance& instance) {
  OnBrowserAppUpdated(instance);
}

void InstanceRegistryUpdater::OnBrowserAppUpdated(
    const BrowserAppInstance& instance) {
  InstanceState state =
      GetState(instance.window->IsVisible(),
               instance.is_browser_active() && instance.is_web_contents_active);
  OnInstance(instance.id, instance.app_id, instance.window, state);
}

void InstanceRegistryUpdater::OnBrowserAppRemoved(
    const BrowserAppInstance& instance) {
  OnInstance(instance.id, instance.app_id, instance.window,
             InstanceState::kDestroyed);
}

void InstanceRegistryUpdater::OnWindowInitialized(aura::Window* window) {
  window_observations_.AddObservation(window);
}

void InstanceRegistryUpdater::OnWindowVisibilityChanged(aura::Window* window,
                                                        bool visible) {
  if (!crosapi::browser_util::IsLacrosWindow(window) &&
      !IsAshBrowserWindow(window)) {
    return;
  }
  for (const BrowserAppInstance* instance :
       browser_app_instance_registry_->SelectAppInstances(
           [window](const BrowserAppInstance& instance) {
             return instance.window == window;
           })) {
    OnBrowserAppUpdated(*instance);
  }
  for (const BrowserWindowInstance* instance :
       browser_app_instance_registry_->SelectWindowInstances(
           [window](const BrowserWindowInstance& instance) {
             return instance.window == window;
           })) {
    OnBrowserWindowUpdated(*instance);
  }
}

void InstanceRegistryUpdater::OnWindowDestroying(aura::Window* window) {
  window_observations_.RemoveObservation(window);
}

void InstanceRegistryUpdater::OnInstance(
    const base::UnguessableToken& instance_id,
    const std::string& app_id,
    aura::Window* window,
    InstanceState state) {
  auto instance = std::make_unique<apps::Instance>(app_id, instance_id, window);
  instance->UpdateState(state, base::Time::Now());
  instance_registry_->OnInstance(std::move(instance));
}

}  // namespace apps