chromium/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_page_handler.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/webui/ash/settings/pages/files/google_drive_page_handler.h"

#include <optional>

#include "base/strings/utf_string_conversions.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/ash/drive/drive_integration_service.h"
#include "chrome/browser/ash/drive/file_system_util.h"
#include "chrome/browser/ui/webui/ash/settings/pages/files/mojom/google_drive_handler.mojom.h"
#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "ui/base/text/bytes_formatting.h"

namespace ash::settings {
namespace {

using drive::DriveIntegrationService;
using drivefs::pinning::PinningManager;
using drivefs::pinning::Progress;
using google_drive::mojom::Status;
using google_drive::mojom::StatusPtr;

StatusPtr CreateStatusPtr(const Progress& progress) {
  StatusPtr status = Status::New();
  status->required_space =
      (progress.required_space >= 0)
          ? base::UTF16ToUTF8(ui::FormatBytes(progress.required_space))
          : "";
  status->free_space =
      (progress.free_space >= 0)
          ? base::UTF16ToUTF8(ui::FormatBytes(progress.free_space))
          : "";
  status->stage = progress.stage;
  status->listed_files = progress.listed_files;
  status->is_error = progress.IsError();
  return status;
}

}  // namespace

GoogleDrivePageHandler::GoogleDrivePageHandler(
    mojo::PendingReceiver<google_drive::mojom::PageHandler> receiver,
    mojo::PendingRemote<google_drive::mojom::Page> page,
    Profile* profile)
    : profile_(profile),
      page_(std::move(page)),
      receiver_(this, std::move(receiver)) {
  if (DriveIntegrationService* const service = GetDriveService()) {
    Observe(service);
  }
}

GoogleDrivePageHandler::~GoogleDrivePageHandler() = default;

void GoogleDrivePageHandler::CalculateRequiredSpace() {
  PinningManager* const pinning_manager = GetPinningManager();
  if (!pinning_manager) {
    page_->OnServiceUnavailable();
    return;
  }

  NotifyProgress(pinning_manager->GetProgress());
  if (!pinning_manager->CalculateRequiredSpace()) {
    page_->OnServiceUnavailable();
    return;
  }
}

void GoogleDrivePageHandler::NotifyProgress(const Progress& progress) {
  page_->OnProgress(CreateStatusPtr(progress));
}

DriveIntegrationService* GoogleDrivePageHandler::GetDriveService() {
  DriveIntegrationService* const service =
      drive::DriveIntegrationServiceFactory::FindForProfile(profile_);
  return service && service->IsMounted() ? service : nullptr;
}

PinningManager* GoogleDrivePageHandler::GetPinningManager() {
  DriveIntegrationService* const service = GetDriveService();
  return service ? service->GetPinningManager() : nullptr;
}

void GoogleDrivePageHandler::OnBulkPinProgress(const Progress& progress) {
  if (!GetPinningManager()) {
    page_->OnServiceUnavailable();
    return;
  }

  NotifyProgress(progress);
}

void GoogleDrivePageHandler::GetContentCacheSize(
    GetContentCacheSizeCallback callback) {
  if (!GetDriveService()) {
    page_->OnServiceUnavailable();
    std::move(callback).Run(std::nullopt);
    return;
  }

  const base::FilePath content_cache_path =
      GetDriveService()->GetDriveFsContentCachePath();

  base::ThreadPool::PostTaskAndReplyWithResult(
      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
      base::BindOnce(&drive::util::ComputeDriveFsContentCacheSize,
                     content_cache_path),
      base::BindOnce(&GoogleDrivePageHandler::OnGetContentCacheSize,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void GoogleDrivePageHandler::OnGetContentCacheSize(
    GetContentCacheSizeCallback callback,
    int64_t size) {
  if (size < 0) {
    std::move(callback).Run(std::nullopt);
    return;
  }
  std::move(callback).Run(base::UTF16ToUTF8(ui::FormatBytes(size)));
}

void GoogleDrivePageHandler::ClearPinnedFiles(
    ClearPinnedFilesCallback callback) {
  if (!GetDriveService()) {
    std::move(callback).Run();
    page_->OnServiceUnavailable();
    return;
  }

  // If Drive crashes, this callback may not get invoked so in that instance
  // ensure it gets invoked with drve::FILE_ERROR_ABORT to indicate that the
  // call has been aborted.
  auto on_clear_callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
      base::BindOnce(&GoogleDrivePageHandler::OnClearPinnedFiles,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
      drive::FILE_ERROR_ABORT);
  GetDriveService()->ClearOfflineFiles(std::move(on_clear_callback));
}

void GoogleDrivePageHandler::OnClearPinnedFiles(
    ClearPinnedFilesCallback callback,
    drive::FileError error) {
  std::move(callback).Run();
}

void GoogleDrivePageHandler::RecordBulkPinningEnabledMetric() {
  drivefs::pinning::RecordBulkPinningEnabledSource(
      drivefs::pinning::BulkPinningEnabledSource::kSystemSettings);
}

}  // namespace ash::settings