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

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

#include <string>

#include "ash/public/cpp/desk_template.h"
#include "ash/wm/desks/desk.h"
#include "ash/wm/desks/desks_controller.h"
#include "base/functional/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/uuid.h"
#include "base/value_iterators.h"
#include "chrome/browser/chromeos/extensions/wm/wm_desks_private_feature_ash.h"
#include "chrome/browser/ui/ash/desks/desks_client.h"

namespace extensions {

namespace {
std::string GetStringError(DesksClient::DeskActionError error) {
  switch (error) {
    case DesksClient::DeskActionError::kStorageError:
      return "StorageError";
    case DesksClient::DeskActionError::kNoCurrentUserError:
      return "NoCurrentUserError";
    case DesksClient::DeskActionError::kBadProfileError:
      return "BadProfileError";
    case DesksClient::DeskActionError::kResourceNotFoundError:
      return "ResourceNotFoundError";
    case DesksClient::DeskActionError::kInvalidIdError:
      return "InvalidIdError";
    case DesksClient::DeskActionError::kDesksBeingModifiedError:
      return "DeskBeingModifiedError";
    case DesksClient::DeskActionError::kDesksCountCheckFailedError:
      return "DesksCountCheckFailedError";
    case DesksClient::DeskActionError::kUnknownError:
      return "UnknownError";
  }
}

api::wm_desks_private::SavedDeskType GetSavedDeskTypeFromDeskTemplateType(
    const ash::DeskTemplateType type) {
  switch (type) {
    case ash::DeskTemplateType::kTemplate:
      return api::wm_desks_private::SavedDeskType::kTemplate;
    case ash::DeskTemplateType::kSaveAndRecall:
      return api::wm_desks_private::SavedDeskType::kSaveAndRecall;
    case ash::DeskTemplateType::kFloatingWorkspace:
      // Desk API does not save/restore Floating Workspace.
      return api::wm_desks_private::SavedDeskType::kUnknown;
    case ash::DeskTemplateType::kUnknown:
      return api::wm_desks_private::SavedDeskType::kUnknown;
  }
}

api::wm_desks_private::Desk GetDeskFromAshDesk(const ash::Desk& ash_desk) {
  api::wm_desks_private::Desk target;
  target.desk_name = base::UTF16ToUTF8(ash_desk.name());
  target.desk_uuid = ash_desk.uuid().AsLowercaseString();
  return target;
}

api::wm_desks_private::SavedDesk GetSavedDeskFromAshDeskTemplate(
    const ash::DeskTemplate& desk_template) {
  api::wm_desks_private::SavedDesk out_api_desk;
  out_api_desk.saved_desk_uuid = desk_template.uuid().AsLowercaseString();
  out_api_desk.saved_desk_name =
      base::UTF16ToUTF8(desk_template.template_name());
  out_api_desk.saved_desk_type =
      GetSavedDeskTypeFromDeskTemplateType(desk_template.type());
  return out_api_desk;
}

}  // namespace

WMDesksPrivateFeatureAsh::WMDesksPrivateFeatureAsh() = default;

WMDesksPrivateFeatureAsh::~WMDesksPrivateFeatureAsh() = default;

void WMDesksPrivateFeatureAsh::GetDeskTemplateJson(
    const base::Uuid& template_uuid,
    Profile* profile,
    GetDeskTemplateJsonCallback callback) {
  DesksClient::Get()->GetTemplateJson(
      template_uuid, profile,
      base::BindOnce(
          [](GetDeskTemplateJsonCallback callback,
             std::optional<DesksClient::DeskActionError> error,
             const base::Value& template_json) {
            if (error) {
              std::move(callback).Run(GetStringError(error.value()), {});
            } else {
              std::move(callback).Run({}, template_json.Clone());
            }
          },
          std::move(callback)));
}

void WMDesksPrivateFeatureAsh::LaunchDesk(std::string desk_name,
                                          LaunchDeskCallback callback) {
  auto result =
      DesksClient::Get()->LaunchEmptyDesk(base::UTF8ToUTF16(desk_name));
  if (!result.has_value()) {
    std::move(callback).Run(GetStringError(result.error()), {});
    return;
  }
  std::move(callback).Run({}, result.value());
}

void WMDesksPrivateFeatureAsh::RemoveDesk(const base::Uuid& desk_uuid,
                                          bool combine_desk,
                                          bool allow_undo,
                                          RemoveDeskCallback callback) {
  ash::DeskCloseType close_type =
      combine_desk ? ash::DeskCloseType::kCombineDesks
                   : (allow_undo ? ash::DeskCloseType::kCloseAllWindowsAndWait
                                 : ash::DeskCloseType::kCloseAllWindows);
  auto error = DesksClient::Get()->RemoveDesk(desk_uuid, close_type);
  std::move(callback).Run(error ? GetStringError(error.value()) : "");
}

void WMDesksPrivateFeatureAsh::SetAllDeskProperty(
    int32_t window_id,
    bool all_desks,
    SetAllDeskPropertyCallback callback) {
  auto error = DesksClient::Get()->SetAllDeskPropertyByBrowserSessionId(
      SessionID::FromSerializedValue(window_id), all_desks);
  std::move(callback).Run(error ? GetStringError(error.value()) : "");
}

void WMDesksPrivateFeatureAsh::GetAllDesks(GetAllDesksCallback callback) {
  auto result = DesksClient::Get()->GetAllDesks();
  if (!result.has_value()) {
    std::move(callback).Run(GetStringError(result.error()), {});
    return;
  }
  std::vector<api::wm_desks_private::Desk> api_desks;
  for (const ash::Desk* desk : result.value()) {
    api_desks.push_back(GetDeskFromAshDesk(*desk));
  }
  std::move(callback).Run({}, std::move(api_desks));
}

void WMDesksPrivateFeatureAsh::SaveActiveDesk(SaveActiveDeskCallback callback) {
  DesksClient::Get()->CaptureActiveDeskAndSaveTemplate(
      base::BindOnce(
          [](SaveActiveDeskCallback callback,
             std::optional<DesksClient::DeskActionError> error,
             std::unique_ptr<ash::DeskTemplate> desk_template) {
            // Note that we want to phase out the concept of `template` in
            // external interface. Use `saved_desk` model instead of template.
            if (error) {
              std::move(callback).Run(GetStringError(error.value()), {});
            } else {
              api::wm_desks_private::SavedDesk saved_desk =
                  GetSavedDeskFromAshDeskTemplate(*desk_template);
              std::move(callback).Run({}, std::move(saved_desk));
            }
          },
          std::move(callback)),
      ash::DeskTemplateType::kSaveAndRecall);
}

void WMDesksPrivateFeatureAsh::DeleteSavedDesk(
    const base::Uuid& desk_uuid,
    DeleteSavedDeskCallback callback) {
  DesksClient::Get()->DeleteDeskTemplate(
      desk_uuid,
      base::BindOnce(
          [](DeleteSavedDeskCallback callback,
             std::optional<DesksClient::DeskActionError> error) {
            std::move(callback).Run(error ? GetStringError(error.value()) : "");
          },
          std::move(callback)));
}

void WMDesksPrivateFeatureAsh::RecallSavedDesk(
    const base::Uuid& desk_uuid,
    RecallSavedDeskCallback callback) {
  DesksClient::Get()->LaunchDeskTemplate(
      desk_uuid, base::BindOnce(
                     [](RecallSavedDeskCallback callback,
                        std::optional<DesksClient::DeskActionError> error,
                        const base::Uuid& desk_Id) {
                       if (error) {
                         std::move(callback).Run(GetStringError(error.value()),
                                                 {});
                       } else {
                         std::move(callback).Run({}, std::move(desk_Id));
                       }
                     },
                     std::move(callback)));
}

void WMDesksPrivateFeatureAsh::GetSavedDesks(GetSavedDesksCallback callback) {
  DesksClient::Get()->GetDeskTemplates(base::BindOnce(
      [](GetSavedDesksCallback callback,
         std::optional<DesksClient::DeskActionError> error,
         const std::vector<raw_ptr<const ash::DeskTemplate,
                                   VectorExperimental>>& desk_templates) {
        if (error) {
          std::move(callback).Run(GetStringError(error.value()), {});
        } else {
          std::vector<api::wm_desks_private::SavedDesk> api_templates;
          for (const ash::DeskTemplate* desk_template : desk_templates) {
            api::wm_desks_private::SavedDesk saved_desk =
                GetSavedDeskFromAshDeskTemplate(*desk_template);
            api_templates.push_back(std::move(saved_desk));
          }
          std::move(callback).Run({}, std::move(api_templates));
        }
      },
      std::move(callback)));
}

void WMDesksPrivateFeatureAsh::GetActiveDesk(GetActiveDeskCallback callback) {
  base::Uuid desk_id = DesksClient::Get()->GetActiveDesk();
  std::move(callback).Run({}, desk_id);
}

void WMDesksPrivateFeatureAsh::SwitchDesk(const base::Uuid& desk_uuid,
                                          SwitchDeskCallback callback) {
  auto error = DesksClient::Get()->SwitchDesk(desk_uuid);
  std::move(callback).Run(error ? GetStringError(error.value()) : "");
}

void WMDesksPrivateFeatureAsh::GetDeskByID(const base::Uuid& desk_uuid,
                                           GetDeskByIDCallback callback) {
  auto result = DesksClient::Get()->GetDeskByID(desk_uuid);
  if (!result.has_value()) {
    std::move(callback).Run(GetStringError(result.error()), {});
    return;
  }
  api::wm_desks_private::Desk desk = GetDeskFromAshDesk(*result.value());
  std::move(callback).Run("", std::move(desk));
}

}  // namespace extensions