| // 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 "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::kSharesheetButton): |
| return sharesheet::LaunchSource::kFilesAppShareButton; |
| case (SharesheetLaunchSource::kContextMenu): |
| return sharesheet::LaunchSource::kFilesAppContextMenu; |
| case (SharesheetLaunchSource::kUnknown): |
| case (SharesheetLaunchSource::kNone): |
| return sharesheet::LaunchSource::kUnknown; |
| } |
| } |
| |
| } // namespace |
| |
| namespace extensions { |
| |
| FileManagerPrivateSharesheetHasTargetsFunction:: |
| FileManagerPrivateSharesheetHasTargetsFunction() = default; |
| |
| FileManagerPrivateSharesheetHasTargetsFunction:: |
| ~FileManagerPrivateSharesheetHasTargetsFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| FileManagerPrivateSharesheetHasTargetsFunction::Run() { |
| using extensions::api::file_manager_private::SharesheetHasTargets::Params; |
| const std::optional<Params> params = Params::Create(args()); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| if (params->file_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->file_urls) { |
| const GURL url(url_as_string); |
| storage::FileSystemURL file_system_url( |
| file_system_context->CrackURLInFirstPartyContext(url)); |
| 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( |
| &FileManagerPrivateSharesheetHasTargetsFunction::OnMimeTypesCollected, |
| this)); |
| return RespondLater(); |
| } |
| |
| void FileManagerPrivateSharesheetHasTargetsFunction::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:: |
| SharesheetHasTargets::Results::Create(result))); |
| return; |
| } |
| |
| if (file_system_urls_.size() == 1 && |
| file_system_urls_[0].type() == storage::kFileSystemTypeDriveFs) { |
| using drive::util::ConnectionStatus; |
| const ConnectionStatus status = drive::util::GetDriveConnectionStatus( |
| Profile::FromBrowserContext(browser_context())); |
| |
| using enum ConnectionStatus; |
| if (status == kMetered || status == kConnected) { |
| file_manager::util::SingleEntryPropertiesGetterForDriveFs::Start( |
| file_system_urls_[0], profile_, |
| base::BindOnce(&FileManagerPrivateSharesheetHasTargetsFunction:: |
| OnDrivePropertyCollected, |
| this, std::move(mime_types))); |
| return; |
| } |
| } |
| result = sharesheet_service->HasShareTargets( |
| apps_util::MakeShareIntent(urls_, *mime_types)); |
| Respond(ArgumentList(extensions::api::file_manager_private:: |
| SharesheetHasTargets::Results::Create(result))); |
| } |
| |
| void FileManagerPrivateSharesheetHasTargetsFunction::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:: |
| 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(&FileManagerPrivateSharesheetHasTargetsFunction:: |
| OnIsDirectoryCollected, |
| this, std::move(mime_types), std::move(properties))); |
| } |
| |
| void FileManagerPrivateSharesheetHasTargetsFunction::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)); |
| Respond(ArgumentList(extensions::api::file_manager_private:: |
| SharesheetHasTargets::Results::Create(result))); |
| } |
| |
| FileManagerPrivateInvokeSharesheetFunction:: |
| FileManagerPrivateInvokeSharesheetFunction() = default; |
| |
| FileManagerPrivateInvokeSharesheetFunction:: |
| ~FileManagerPrivateInvokeSharesheetFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| FileManagerPrivateInvokeSharesheetFunction::Run() { |
| using extensions::api::file_manager_private::InvokeSharesheet::Params; |
| const std::optional<Params> params = Params::Create(args()); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| if (params->file_urls.empty()) { |
| return RespondNow(Error("No URLs provided")); |
| } |
| |
| if (params->dlp_source_urls.size() != params->file_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->file_urls) { |
| const GURL url(url_string); |
| storage::FileSystemURL file_system_url( |
| file_system_context->CrackURLInFirstPartyContext(url)); |
| 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( |
| &FileManagerPrivateInvokeSharesheetFunction::OnMimeTypesCollected, |
| this, GetLaunchSource(params->launch_source))); |
| |
| return RespondLater(); |
| } |
| |
| void FileManagerPrivateInvokeSharesheetFunction::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) { |
| using drive::util::ConnectionStatus; |
| const ConnectionStatus status = drive::util::GetDriveConnectionStatus( |
| Profile::FromBrowserContext(browser_context())); |
| |
| using enum ConnectionStatus; |
| if (status == kMetered || status == kConnected) { |
| file_manager::util::SingleEntryPropertiesGetterForDriveFs::Start( |
| file_system_urls_[0], profile_, |
| base::BindOnce(&FileManagerPrivateInvokeSharesheetFunction:: |
| OnDrivePropertyCollected, |
| this, launch_source, std::move(mime_types))); |
| return; |
| } |
| } |
| |
| sharesheet_service->ShowBubble( |
| GetSenderWebContents(), |
| apps_util::MakeShareIntent(urls_, *mime_types, dlp_source_urls_), |
| launch_source, base::DoNothing()); |
| Respond(NoArguments()); |
| } |
| |
| void FileManagerPrivateInvokeSharesheetFunction::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( |
| &FileManagerPrivateInvokeSharesheetFunction::OnIsDirectoryCollected, |
| this, launch_source, std::move(mime_types), std::move(properties))); |
| } |
| |
| void FileManagerPrivateInvokeSharesheetFunction::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), |
| launch_source, base::DoNothing()); |
| Respond(NoArguments()); |
| } |
| |
| } // namespace extensions |