chromium/ash/system/mahi/fake_mahi_manager.cc

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

#include "ash/system/mahi/fake_mahi_manager.h"

#include <utility>
#include <vector>

#include "ash/public/cpp/new_window_delegate.h"
#include "ash/system/mahi/mahi_constants.h"
#include "ash/system/mahi/mahi_panel_widget.h"
#include "ash/system/mahi/mahi_ui_controller.h"
#include "base/functional/bind.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "ui/display/screen.h"
#include "url/gurl.h"

namespace ash {

namespace {

// If true, callbacks passed to `FakeMahiManager` are handled asyncly with zero
// time duration.
bool g_use_zero_duration = false;

// Constants -------------------------------------------------------------------

constexpr char16_t kDefaultAnswer[] = u"Fake answer";

constexpr char16_t kDefaultContentTitle[] = u"fake content title";

constexpr char kDefaultContentUrl[] = "https://en.wikipedia.org/wiki/Wombat";

const std::vector<chromeos::MahiOutline> kDefaultOutlines(
    {chromeos::MahiOutline(/*id=*/1, u"Outline 1"),
     chromeos::MahiOutline(/*id=*/2, u"Outline 2"),
     chromeos::MahiOutline(/*id=*/3, u"Outline 3"),
     chromeos::MahiOutline(/*id=*/4, u"Outline 4"),
     chromeos::MahiOutline(/*id=*/5, u"Outline 5")});

constexpr char16_t kDefaultSummaryText[] =
    u"fake summary text\nfake summary text\nfake summary text\nfake summary "
    u"text\nfake summary text";

constexpr char kMahiSettingsUrl[] =
    "chrome://os-settings/systemPreferences?settingId=612";

}  // namespace

using crosapi::mojom::MahiContextMenuActionType;

FakeMahiManager::FakeMahiManager() = default;

FakeMahiManager::~FakeMahiManager() = default;

std::u16string FakeMahiManager::GetContentTitle() {
  return content_title_.value_or(kDefaultContentTitle);
}

gfx::ImageSkia FakeMahiManager::GetContentIcon() {
  return content_icon_;
}

GURL FakeMahiManager::GetContentUrl() {
  return GURL(kDefaultContentUrl);
}

void FakeMahiManager::GetSummary(MahiSummaryCallback callback) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(std::move(callback),
                     summary_text_.value_or(kDefaultSummaryText),
                     chromeos::MahiResponseStatus::kSuccess),
      g_use_zero_duration
          ? base::TimeDelta()
          : base::Seconds(
                mahi_constants::kFakeMahiManagerLoadSummaryDelaySeconds));
}

void FakeMahiManager::GetOutlines(MahiOutlinesCallback callback) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), kDefaultOutlines,
                     chromeos::MahiResponseStatus::kSuccess),
      g_use_zero_duration
          ? base::TimeDelta()
          : base::Seconds(
                mahi_constants::kFakeMahiManagerLoadOutlinesDelaySeconds));
}

void FakeMahiManager::AnswerQuestion(const std::u16string& question,
                                     bool current_panel_content,
                                     MahiAnswerQuestionCallback callback) {
  asked_question_ = question;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), answer_text_.value_or(kDefaultAnswer),
                     chromeos::MahiResponseStatus::kSuccess),
      g_use_zero_duration
          ? base::TimeDelta()
          : base::Seconds(
                mahi_constants::kFakeMahiManagerLoadAnswerDelaySeconds));
}

void FakeMahiManager::OnContextMenuClicked(
    crosapi::mojom::MahiContextMenuRequestPtr context_menu_request) {
  switch (context_menu_request->action_type) {
    case MahiContextMenuActionType::kSummary:
    case MahiContextMenuActionType::kOutline:
      // TODO(b/318565610): Update the behaviour of kOutline.
      OpenMahiPanel(
          context_menu_request->display_id,
          context_menu_request->mahi_menu_bounds.value_or(gfx::Rect()));

      return;
    case MahiContextMenuActionType::kQA:
      OpenMahiPanel(context_menu_request->display_id,
                    context_menu_request->mahi_menu_bounds.has_value()
                        ? context_menu_request->mahi_menu_bounds.value()
                        : gfx::Rect());

      // Ask question.
      if (!context_menu_request->question) {
        return;
      }

      // Because we call `MahiUiController::SendQuestion` right after
      // opening the panel here, `SendQuestion` will cancel the call to get
      // summary due to `MahiUiController::InvalidatePendingRequests()`. Thus,
      // we need to update the summary after answering the question to make sure
      // that user gets summary when navigating back to the summary UI
      // (b/345621992).
      ui_controller_.SendQuestion(
          context_menu_request->question.value(),
          /*current_panel_content=*/true,
          MahiUiController::QuestionSource::kMenuView,
          /*update_summary_after_answer_question=*/true);
      return;
    case MahiContextMenuActionType::kSettings:
      NewWindowDelegate::GetInstance()->OpenUrl(
          GURL(kMahiSettingsUrl),
          NewWindowDelegate::OpenUrlFrom::kUserInteraction,
          NewWindowDelegate::Disposition::kNewForegroundTab);
      return;
    case MahiContextMenuActionType::kNone:
      return;
  }
}

void FakeMahiManager::OpenMahiPanel(int64_t display_id,
                                    const gfx::Rect& mahi_menu_bounds) {
  ui_controller_.OpenMahiPanel(display_id, mahi_menu_bounds);
}

bool FakeMahiManager::IsEnabled() {
  return true;
}

bool FakeMahiManager::AllowRepeatingAnswers() {
  return false;
}

void FakeMahiManager::AnswerQuestionRepeating(
    const std::u16string& question,
    bool current_panel_content,
    MahiAnswerQuestionCallbackRepeating callback) {}

void FakeMahiManager::SetMediaAppPDFFocused() {}

// ScopedFakeMahiManagerZeroDuration -------------------------------------------

ScopedFakeMahiManagerZeroDuration::ScopedFakeMahiManagerZeroDuration() {
  CHECK(!g_use_zero_duration);
  g_use_zero_duration = true;
}

ScopedFakeMahiManagerZeroDuration::~ScopedFakeMahiManagerZeroDuration() {
  CHECK(g_use_zero_duration);
  g_use_zero_duration = false;
}

}  // namespace ash