// 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/ash/file_manager/virtual_file_tasks.h"
#include <initializer_list>
#include <vector>
#include "base/containers/contains.h"
#include "base/no_destructor.h"
#include "chrome/browser/ash/file_manager/app_id.h"
#include "chrome/browser/ash/file_manager/file_tasks.h"
#include "chrome/browser/ash/file_manager/virtual_tasks/drive_upload_virtual_task.h"
#include "chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task.h"
#include "chrome/browser/ash/file_manager/virtual_tasks/ms365_virtual_task.h"
#include "components/services/app_service/public/cpp/intent_util.h"
namespace file_manager::file_tasks {
namespace {
// The set of virtual tasks is statically determined. Tasks can turn themselves
// on or off dynamically by implementing |IsEnabled()|.
const std::vector<VirtualTask*>& GetVirtualTasks() {
static const base::NoDestructor<std::vector<VirtualTask*>> virtual_tasks(
std::initializer_list<VirtualTask*>({
new InstallIsolatedWebAppVirtualTask(),
new Ms365VirtualTask(),
new DocsUploadVirtualTask(),
new SheetsUploadVirtualTask(),
new SlidesUploadVirtualTask(),
}));
if (!GetTestVirtualTasks().empty()) {
return GetTestVirtualTasks();
}
return *virtual_tasks;
}
bool LooksLikeVirtualTask(const TaskDescriptor& task) {
return task.app_id == kFileManagerSwaAppId &&
task.task_type == TASK_TYPE_WEB_APP;
}
// Validates that each entry from `entries` matches any mime type from
// `mime_types`.
bool AllEntriesMatchAtLeastOneMimeType(
const std::vector<extensions::EntryInfo>& entries,
const std::vector<std::string>& mime_types) {
return base::ranges::all_of(
entries,
[&](const std::string& entry_mime_type) {
return base::ranges::any_of(
mime_types, [&](const std::string& mime_type) {
return apps_util::MimeTypeMatched(entry_mime_type, mime_type);
});
},
&extensions::EntryInfo::mime_type);
}
// Validates that each file url from `file_urls` matches any file extension from
// `file_extensions`
bool AllUrlsMatchAtLeastOneFileExtension(
const std::vector<GURL>& file_urls,
const std::vector<std::string>& file_extensions) {
return base::ranges::all_of(
file_urls,
[&](const std::string& file_name) {
return base::ranges::any_of(
file_extensions, [&](const std::string& file_extension) {
return apps_util::ExtensionMatched(file_name, file_extension);
});
},
&GURL::ExtractFileName);
}
} // namespace
void MatchVirtualTasks(Profile* profile,
const std::vector<extensions::EntryInfo>& entries,
const std::vector<GURL>& file_urls,
const std::vector<std::string>& dlp_source_urls,
std::vector<FullTaskDescriptor>* result_list) {
DCHECK_EQ(entries.size(), file_urls.size());
if (entries.empty()) {
return;
}
for (const VirtualTask* virtual_task : GetVirtualTasks()) {
if (virtual_task->IsEnabled(profile) &&
virtual_task->Matches(entries, file_urls)) {
// TODO(b/284800493): Correct values below.
result_list->emplace_back(
TaskDescriptor{kFileManagerSwaAppId, TASK_TYPE_WEB_APP,
virtual_task->id()},
virtual_task->title(), virtual_task->icon_url(),
/* is_default=*/false,
/* is_generic_file_handler=*/false,
/* is_file_extension_match=*/false,
virtual_task->IsDlpBlocked(dlp_source_urls));
}
}
}
bool ExecuteVirtualTask(Profile* profile,
const TaskDescriptor& task,
const std::vector<FileSystemURL>& file_urls) {
auto* virtual_task = FindVirtualTask(task);
if (!virtual_task || !virtual_task->IsEnabled(profile)) {
return false;
}
return virtual_task->Execute(profile, task, file_urls);
}
bool IsVirtualTask(const TaskDescriptor& task) {
return LooksLikeVirtualTask(task) &&
base::Contains(GetVirtualTasks(), task.action_id, &VirtualTask::id);
}
VirtualTask* FindVirtualTask(const TaskDescriptor& task) {
if (!LooksLikeVirtualTask(task)) {
return nullptr;
}
const auto& tasks = GetVirtualTasks();
auto itr = base::ranges::find(tasks, task.action_id, &VirtualTask::id);
if (itr == tasks.end()) {
return nullptr;
}
return *itr;
}
std::vector<VirtualTask*>& GetTestVirtualTasks() {
static base::NoDestructor<std::vector<VirtualTask*>> virtual_tasks;
return *virtual_tasks;
}
VirtualTask::VirtualTask() = default;
VirtualTask::~VirtualTask() = default;
bool VirtualTask::Matches(const std::vector<extensions::EntryInfo>& entries,
const std::vector<GURL>& file_urls) const {
// Try to match mime types
bool mime_types_matched =
AllEntriesMatchAtLeastOneMimeType(entries, matcher_mime_types_);
// Try to match extensions
bool extensions_matched =
AllUrlsMatchAtLeastOneFileExtension(file_urls, matcher_file_extensions_);
// TODO(b/284800493): Should this be able to mix and match mimes and
// extensions too?
return mime_types_matched || extensions_matched;
}
} // namespace file_manager::file_tasks