chromium/chrome/browser/ui/ash/game_dashboard/chrome_game_dashboard_delegate.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/ui/ash/game_dashboard/chrome_game_dashboard_delegate.h"

#include "ash/components/arc/arc_util.h"
#include "ash/components/arc/compat_mode/arc_resize_lock_manager.h"
#include "ash/components/arc/compat_mode/compat_mode_button_controller.h"
#include "ash/components/arc/session/connection_holder.h"
#include "ash/public/cpp/multi_user_window_manager.h"
#include "chrome/browser/apps/app_service/metrics/app_platform_metrics.h"
#include "chrome/browser/ash/app_list/arc/arc_app_list_prefs.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/scalable_iph/scalable_iph_factory.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
#include "chromeos/ash/components/scalable_iph/scalable_iph.h"
#include "components/user_manager/user_manager.h"

ChromeGameDashboardDelegate::ChromeGameDashboardDelegate() = default;

ChromeGameDashboardDelegate::~ChromeGameDashboardDelegate() = default;

void ChromeGameDashboardDelegate::GetIsGame(const std::string& app_id,
                                            IsGameCallback callback) {
  if (arc::GetArcAndroidSdkVersionAsInt() <= arc::kArcVersionP) {
    // Android sends a list of `arc::mojom::AppInfo` objects to Chrome, and is
    // stored in `ArcAppListPrefs`. crrev.com/c/4419690 extended the AppInfo
    // object to include the `app_category` field. Since ARC-P was frozen, that
    // change was never ported to it. This delegate cannot determine whether
    // the given `app-id`'s category on devices running ARC P. Assume the app is
    // not a game.
    std::move(callback).Run(/*is_game=*/false);
    return;
  }

  // Get the app category from ArcAppListPrefs.
  auto* profile = ProfileManager::GetPrimaryUserProfile();
  CHECK(profile);
  auto* arc_app_list_prefs = ArcAppListPrefs::Get(profile);
  if (!arc_app_list_prefs) {
    // If there's no ArcAppListPrefs, assume the app is not a game.
    std::move(callback).Run(/*is_game=*/false);
    return;
  }
  const auto app_category = arc_app_list_prefs->GetAppCategory(app_id);
  // If the category is anything except `kUndefined`, fire the callback,
  // otherwise, retrieve the category from ARC.
  if (app_category != arc::mojom::AppCategory::kUndefined) {
    std::move(callback).Run(app_category == arc::mojom::AppCategory::kGame);
    return;
  }

  auto* app_instance = ARC_GET_INSTANCE_FOR_METHOD(
      arc_app_list_prefs->app_connection_holder(), GetAppCategory);
  if (!app_instance) {
    // If there's no app instance, assume the app is not a game.
    std::move(callback).Run(/*is_game=*/false);
    return;
  }

  app_instance->GetAppCategory(
      arc_app_list_prefs->GetAppPackageName(app_id),
      base::BindOnce(&ChromeGameDashboardDelegate::OnReceiveAppCategory,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

std::string ChromeGameDashboardDelegate::GetArcAppName(
    const std::string& app_id) const {
  // Get the app category from ArcAppListPrefs.
  auto* profile = ProfileManager::GetPrimaryUserProfile();
  CHECK(profile);

  auto app_info = ArcAppListPrefs::Get(profile)->GetApp(app_id);
  if (!app_info) {
    LOG(ERROR) << "Failed to get app info: " << app_id << ".";
    return std::string();
  }
  return app_info->name;
}

void ChromeGameDashboardDelegate::RecordGameWindowOpenedEvent(
    aura::Window* window) {
  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
  CHECK(user_manager);
  if (user_manager->GetActiveUser() != user_manager->GetPrimaryUser()) {
    return;
  }

  ash::MultiUserWindowManager* multi_user_window_manager =
      MultiUserWindowManagerHelper::GetWindowManager();
  if (multi_user_window_manager) {
    // If multi user is not enabled, `MultiUserWindowManagerStub` is set. It
    // returns an invalid account id.
    const AccountId& account_id =
        multi_user_window_manager->GetWindowOwner(window);
    if (account_id.is_valid() &&
        user_manager->GetPrimaryUser()->GetAccountId() != account_id) {
      return;
    }
  }

  Profile* profile = ProfileManager::GetPrimaryUserProfile();
  CHECK(profile);

  scalable_iph::ScalableIph* scalable_iph =
      ScalableIphFactory::GetForBrowserContext(profile);
  if (scalable_iph) {
    scalable_iph->RecordEvent(
        scalable_iph::ScalableIph::Event::kGameWindowOpened);
  }
}

void ChromeGameDashboardDelegate::ShowResizeToggleMenu(aura::Window* window) {
  DCHECK(window) << "Window needed to show compat mode toggle menu.";
  GetCompatModeButtonController()->ShowResizeToggleMenu(
      window,
      /*callback=*/base::DoNothing());
}

ukm::SourceId ChromeGameDashboardDelegate::GetUkmSourceId(
    const std::string& app_id) {
  // Get the ukm source id from apps::AppPlatformMetrics.
  auto* profile = ProfileManager::GetPrimaryUserProfile();
  CHECK(profile);
  return apps::AppPlatformMetrics::GetSourceId(profile, app_id);
}

arc::CompatModeButtonController*
ChromeGameDashboardDelegate::GetCompatModeButtonController() {
  if (!compat_mode_button_controller_) {
    auto* profile = ProfileManager::GetPrimaryUserProfile();
    CHECK(profile) << "Cannot retrieve the CompatModeButtonController without "
                      "a valid user profile.";
    auto* resize_lock_manager =
        arc::ArcResizeLockManager::GetForBrowserContext(profile);
    CHECK(resize_lock_manager) << "Received a null ArcResizeLockManager.";
    compat_mode_button_controller_ =
        resize_lock_manager->compat_mode_button_controller()->GetWeakPtr();
    CHECK(compat_mode_button_controller_)
        << "Received a null CompatModeButtonController from "
           "ArcResizeLockManager.";
  }
  return compat_mode_button_controller_.get();
}

void ChromeGameDashboardDelegate::OnReceiveAppCategory(
    IsGameCallback callback,
    arc::mojom::AppCategory category) {
  std::move(callback).Run(category == arc::mojom::AppCategory::kGame);
}