blob: 339bbcbb54bb034f35042471517493db50193938 [file] [log] [blame]
// Copyright 2020 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/extensions/file_manager/private_api_sharesheet.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "chrome/browser/ash/drive/file_system_util.h"
#include "chrome/browser/ash/extensions/file_manager/private_api_util.h"
#include "chrome/browser/ash/file_manager/fileapi_util.h"
#include "chrome/browser/ash/fileapi/file_system_backend.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sharesheet/sharesheet_service.h"
#include "chrome/browser/sharesheet/sharesheet_service_factory.h"
#include "chrome/common/extensions/api/file_manager_private.h"
#include "chrome/common/extensions/api/file_manager_private_internal.h"
#include "components/drive/drive_api_util.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/api/file_handlers/directory_util.h"
#include "extensions/browser/api/file_handlers/mime_util.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_url.h"
using storage::FileSystemURL;
namespace {
using extensions::api::file_manager_private::SharesheetLaunchSource;
sharesheet::LaunchSource GetLaunchSource(SharesheetLaunchSource launch_source) {
switch (launch_source) {
case (SharesheetLaunchSource::SHARESHEET_LAUNCH_SOURCE_SHARESHEET_BUTTON):
return sharesheet::LaunchSource::kFilesAppShareButton;
case (SharesheetLaunchSource::SHARESHEET_LAUNCH_SOURCE_CONTEXT_MENU):
return sharesheet::LaunchSource::kFilesAppContextMenu;
case (SharesheetLaunchSource::SHARESHEET_LAUNCH_SOURCE_UNKNOWN):
case (SharesheetLaunchSource::SHARESHEET_LAUNCH_SOURCE_NONE):
return sharesheet::LaunchSource::kUnknown;
}
}
} // namespace
namespace extensions {
FileManagerPrivateInternalSharesheetHasTargetsFunction::
FileManagerPrivateInternalSharesheetHasTargetsFunction() = default;
FileManagerPrivateInternalSharesheetHasTargetsFunction::
~FileManagerPrivateInternalSharesheetHasTargetsFunction() = default;
ExtensionFunction::ResponseAction
FileManagerPrivateInternalSharesheetHasTargetsFunction::Run() {
using extensions::api::file_manager_private_internal::SharesheetHasTargets::
Params;
const absl::optional<Params> params = Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params);
if (params->urls.empty()) {
return RespondNow(Error("No URLs provided"));
}
profile_ = Profile::FromBrowserContext(browser_context());
const scoped_refptr<storage::FileSystemContext> file_system_context =
file_manager::util::GetFileSystemContextForRenderFrameHost(
profile_, render_frame_host());
// Collect all the URLs, convert them to GURLs, and crack all the urls into
// file paths.
for (const auto& url_as_string : params->urls) {
const GURL url(url_as_string);
storage::FileSystemURL file_system_url(
file_system_context->CrackURLInFirstPartyContext(url));
if (drive::util::HasHostedDocumentExtension(file_system_url.path())) {
contains_hosted_document_ = true;
}
if (!ash::FileSystemBackend::CanHandleURL(file_system_url)) {
continue;
}
urls_.push_back(url);
file_system_urls_.push_back(file_system_url);
}
mime_type_collector_ =
std::make_unique<app_file_handler_util::MimeTypeCollector>(profile_);
mime_type_collector_->CollectForURLs(
file_system_urls_,
base::BindOnce(&FileManagerPrivateInternalSharesheetHasTargetsFunction::
OnMimeTypesCollected,
this));
return RespondLater();
}
void FileManagerPrivateInternalSharesheetHasTargetsFunction::
OnMimeTypesCollected(std::unique_ptr<std::vector<std::string>> mime_types) {
sharesheet::SharesheetService* sharesheet_service =
sharesheet::SharesheetServiceFactory::GetForProfile(profile_);
bool result = false;
if (!sharesheet_service) {
LOG(ERROR) << "Couldn't get Sharesheet Service for profile";
Respond(ArgumentList(extensions::api::file_manager_private_internal::
SharesheetHasTargets::Results::Create(result)));
return;
}
if (file_system_urls_.size() == 1 &&
file_system_urls_[0].type() == storage::kFileSystemTypeDriveFs) {
auto connection_status = drive::util::GetDriveConnectionStatus(
Profile::FromBrowserContext(browser_context()));
if (connection_status == drive::util::DRIVE_CONNECTED_METERED ||
connection_status == drive::util::DRIVE_CONNECTED) {
file_manager::util::SingleEntryPropertiesGetterForDriveFs::Start(
file_system_urls_[0], profile_, /*requested_properties=*/{},
base::BindOnce(
&FileManagerPrivateInternalSharesheetHasTargetsFunction::
OnDrivePropertyCollected,
this, std::move(mime_types)));
return;
}
}
result = sharesheet_service->HasShareTargets(
apps_util::MakeShareIntent(urls_, *mime_types),
contains_hosted_document_);
Respond(ArgumentList(extensions::api::file_manager_private_internal::
SharesheetHasTargets::Results::Create(result)));
}
void FileManagerPrivateInternalSharesheetHasTargetsFunction::
OnDrivePropertyCollected(
std::unique_ptr<std::vector<std::string>> mime_types,
std::unique_ptr<api::file_manager_private::EntryProperties> properties,
base::File::Error error) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (error != base::File::FILE_OK) {
LOG(ERROR) << "Error reading file properties in Drive: " << error;
Respond(ArgumentList(extensions::api::file_manager_private_internal::
SharesheetHasTargets::Results::Create(false)));
return;
}
is_directory_collector_ =
std::make_unique<app_file_handler_util::IsDirectoryCollector>(profile_);
is_directory_collector_->CollectForEntriesPaths(
std::vector<base::FilePath>{file_system_urls_[0].path()},
base::BindOnce(&FileManagerPrivateInternalSharesheetHasTargetsFunction::
OnIsDirectoryCollected,
this, std::move(mime_types), std::move(properties)));
}
void FileManagerPrivateInternalSharesheetHasTargetsFunction::
OnIsDirectoryCollected(
std::unique_ptr<std::vector<std::string>> mime_types,
std::unique_ptr<api::file_manager_private::EntryProperties> properties,
std::unique_ptr<std::set<base::FilePath>> path_directory_set) {
bool is_directory = path_directory_set->find(file_system_urls_[0].path()) !=
path_directory_set->end();
sharesheet::SharesheetService* sharesheet_service =
sharesheet::SharesheetServiceFactory::GetForProfile(profile_);
GURL share_url =
(properties->can_share && *properties->can_share && properties->share_url)
? GURL(*properties->share_url)
: GURL();
bool result = sharesheet_service->HasShareTargets(
apps_util::MakeShareIntent(urls_[0], (*mime_types)[0], share_url,
is_directory),
contains_hosted_document_);
Respond(ArgumentList(extensions::api::file_manager_private_internal::
SharesheetHasTargets::Results::Create(result)));
}
FileManagerPrivateInternalInvokeSharesheetFunction::
FileManagerPrivateInternalInvokeSharesheetFunction() = default;
FileManagerPrivateInternalInvokeSharesheetFunction::
~FileManagerPrivateInternalInvokeSharesheetFunction() = default;
ExtensionFunction::ResponseAction
FileManagerPrivateInternalInvokeSharesheetFunction::Run() {
using extensions::api::file_manager_private_internal::InvokeSharesheet::
Params;
const absl::optional<Params> params = Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params);
if (params->urls.empty()) {
return RespondNow(Error("No URLs provided"));
}
if (params->dlp_source_urls.size() != params->urls.size()) {
return RespondNow(Error("Mismatching URLs and DLP source URLs provided"));
}
profile_ = Profile::FromBrowserContext(browser_context());
const scoped_refptr<storage::FileSystemContext> file_system_context =
file_manager::util::GetFileSystemContextForRenderFrameHost(
profile_, render_frame_host());
// Collect all the URLs, convert them to GURLs, and crack all the urls into
// file paths.
for (const auto& url_string : params->urls) {
const GURL url(url_string);
storage::FileSystemURL file_system_url(
file_system_context->CrackURLInFirstPartyContext(url));
if (drive::util::HasHostedDocumentExtension(file_system_url.path())) {
contains_hosted_document_ = true;
}
if (!ash::FileSystemBackend::CanHandleURL(file_system_url)) {
continue;
}
urls_.push_back(url);
file_system_urls_.push_back(file_system_url);
}
dlp_source_urls_ = std::move(params->dlp_source_urls);
mime_type_collector_ =
std::make_unique<app_file_handler_util::MimeTypeCollector>(profile_);
mime_type_collector_->CollectForURLs(
file_system_urls_,
base::BindOnce(&FileManagerPrivateInternalInvokeSharesheetFunction::
OnMimeTypesCollected,
this, GetLaunchSource(params->launch_source)));
return RespondLater();
}
void FileManagerPrivateInternalInvokeSharesheetFunction::OnMimeTypesCollected(
sharesheet::LaunchSource launch_source,
std::unique_ptr<std::vector<std::string>> mime_types) {
// On button press show sharesheet bubble.
sharesheet::SharesheetService* sharesheet_service =
sharesheet::SharesheetServiceFactory::GetForProfile(profile_);
if (!sharesheet_service) {
Respond(Error("Cannot find sharesheet service"));
return;
}
if (file_system_urls_.size() == 1 &&
file_system_urls_[0].type() == storage::kFileSystemTypeDriveFs) {
auto connection_status = drive::util::GetDriveConnectionStatus(
Profile::FromBrowserContext(browser_context()));
if (connection_status == drive::util::DRIVE_CONNECTED_METERED ||
connection_status == drive::util::DRIVE_CONNECTED) {
file_manager::util::SingleEntryPropertiesGetterForDriveFs::Start(
file_system_urls_[0], profile_, /*requested_properties=*/{},
base::BindOnce(&FileManagerPrivateInternalInvokeSharesheetFunction::
OnDrivePropertyCollected,
this, launch_source, std::move(mime_types)));
return;
}
}
sharesheet_service->ShowBubble(
GetSenderWebContents(),
apps_util::MakeShareIntent(urls_, *mime_types, dlp_source_urls_),
contains_hosted_document_, launch_source, base::NullCallback());
Respond(NoArguments());
}
void FileManagerPrivateInternalInvokeSharesheetFunction::
OnDrivePropertyCollected(
sharesheet::LaunchSource launch_source,
std::unique_ptr<std::vector<std::string>> mime_types,
std::unique_ptr<api::file_manager_private::EntryProperties> properties,
base::File::Error error) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (error != base::File::FILE_OK) {
Respond(Error("Drive File Error"));
return;
}
is_directory_collector_ =
std::make_unique<app_file_handler_util::IsDirectoryCollector>(profile_);
is_directory_collector_->CollectForEntriesPaths(
std::vector<base::FilePath>{file_system_urls_[0].path()},
base::BindOnce(&FileManagerPrivateInternalInvokeSharesheetFunction::
OnIsDirectoryCollected,
this, launch_source, std::move(mime_types),
std::move(properties)));
}
void FileManagerPrivateInternalInvokeSharesheetFunction::OnIsDirectoryCollected(
sharesheet::LaunchSource launch_source,
std::unique_ptr<std::vector<std::string>> mime_types,
std::unique_ptr<api::file_manager_private::EntryProperties> properties,
std::unique_ptr<std::set<base::FilePath>> path_directory_set) {
bool is_directory = path_directory_set->find(file_system_urls_[0].path()) !=
path_directory_set->end();
sharesheet::SharesheetService* sharesheet_service =
sharesheet::SharesheetServiceFactory::GetForProfile(profile_);
if (!sharesheet_service) {
Respond(Error("Cannot find sharesheet service"));
return;
}
GURL share_url =
(properties->can_share && *properties->can_share && properties->share_url)
? GURL(*properties->share_url)
: GURL();
sharesheet_service->ShowBubble(
GetSenderWebContents(),
apps_util::MakeShareIntent(urls_[0], (*mime_types)[0], share_url,
is_directory),
contains_hosted_document_, launch_source, base::NullCallback());
Respond(NoArguments());
}
} // namespace extensions