123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- // Copyright 2016 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
- #include <iterator>
- #include <utility>
- #include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
- #include "ash/components/arc/audio/arc_audio_bridge.h"
- #include "ash/components/arc/session/arc_bridge_service.h"
- #include "ash/components/arc/session/arc_service_manager.h"
- #include "ash/public/cpp/new_window_delegate.h"
- #include "ash/public/cpp/system/power/power_button_controller_base.h"
- #include "ash/public/cpp/wallpaper/wallpaper_controller.h"
- #include "base/json/json_writer.h"
- #include "base/logging.h"
- #include "base/memory/singleton.h"
- #include "base/memory/weak_ptr.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/strings/string_util.h"
- #include "base/values.h"
- #include "components/arc/common/intent_helper/arc_intent_helper_package.h"
- #include "components/arc/intent_helper/control_camera_app_delegate.h"
- #include "components/arc/intent_helper/intent_constants.h"
- #include "components/arc/intent_helper/open_url_delegate.h"
- #include "components/url_formatter/url_fixer.h"
- #include "net/base/url_util.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "ui/base/layout.h"
- #include "url/url_constants.h"
- namespace arc {
- namespace {
- constexpr const char* kArcSchemes[] = {url::kHttpScheme, url::kHttpsScheme,
- url::kContentScheme, url::kFileScheme,
- url::kMailToScheme};
- // Not owned. Must outlive all ArcIntentHelperBridge instances. Typically this
- // is ChromeNewWindowClient in the browser.
- OpenUrlDelegate* g_open_url_delegate = nullptr;
- ControlCameraAppDelegate* g_control_camera_app_delegate = nullptr;
- // Singleton factory for ArcIntentHelperBridge.
- class ArcIntentHelperBridgeFactory
- : public internal::ArcBrowserContextKeyedServiceFactoryBase<
- ArcIntentHelperBridge,
- ArcIntentHelperBridgeFactory> {
- public:
- // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
- static constexpr const char* kName = "ArcIntentHelperBridgeFactory";
- static ArcIntentHelperBridgeFactory* GetInstance() {
- return base::Singleton<ArcIntentHelperBridgeFactory>::get();
- }
- private:
- friend struct base::DefaultSingletonTraits<ArcIntentHelperBridgeFactory>;
- ArcIntentHelperBridgeFactory() = default;
- ~ArcIntentHelperBridgeFactory() override = default;
- };
- // Keep in sync with ArcIntentHelperOpenType enum in
- // //tools/metrics/histograms/enums.xml.
- enum class ArcIntentHelperOpenType {
- DOWNLOADS = 0,
- URL = 1,
- CUSTOM_TAB = 2,
- WALLPAPER_PICKER = 3,
- VOLUME_CONTROL = 4,
- CHROME_PAGE = 5,
- WEB_APP = 6,
- kMaxValue = WEB_APP,
- };
- // Records Arc.IntentHelper.OpenType UMA histogram.
- void RecordOpenType(ArcIntentHelperOpenType type) {
- UMA_HISTOGRAM_ENUMERATION("Arc.IntentHelper.OpenType", type);
- }
- // These values are persisted to logs. Entries should not be renumbered and
- // numeric values should never be reused.
- enum class OpenIntentAction {
- kUnknown = 0,
- kView = 1,
- kSend = 2,
- kSendMultiple = 3,
- kMaxValue = kSendMultiple,
- };
- void RecordOpenAppIntentAction(const mojom::LaunchIntentPtr& intent) {
- OpenIntentAction action = OpenIntentAction::kUnknown;
- if (intent->action == kIntentActionView) {
- action = OpenIntentAction::kView;
- } else if (intent->action == kIntentActionSend) {
- action = OpenIntentAction::kSend;
- } else if (intent->action == kIntentActionSendMultiple) {
- action = OpenIntentAction::kSendMultiple;
- }
- UMA_HISTOGRAM_ENUMERATION("Arc.IntentHelper.OpenAppWithIntentAction", action);
- }
- // Returns true if a Web App is allowed to be opened for the given URL.
- bool CanOpenWebAppForUrl(const GURL& url) {
- bool is_http_localhost =
- url.SchemeIs(url::kHttpScheme) && net::IsLocalhost(url);
- return url.is_valid() &&
- (url.SchemeIs(url::kHttpsScheme) || is_http_localhost);
- }
- } // namespace
- // static
- ArcIntentHelperBridge* ArcIntentHelperBridge::GetForBrowserContext(
- content::BrowserContext* context) {
- return ArcIntentHelperBridgeFactory::GetForBrowserContext(context);
- }
- // static
- ArcIntentHelperBridge* ArcIntentHelperBridge::GetForBrowserContextForTesting(
- content::BrowserContext* context) {
- return ArcIntentHelperBridgeFactory::GetForBrowserContextForTesting(context);
- }
- // static
- BrowserContextKeyedServiceFactory* ArcIntentHelperBridge::GetFactory() {
- return ArcIntentHelperBridgeFactory::GetInstance();
- }
- // static
- std::string ArcIntentHelperBridge::AppendStringToIntentHelperPackageName(
- const std::string& to_append) {
- return base::JoinString({kArcIntentHelperPackageName, to_append}, ".");
- }
- // static
- void ArcIntentHelperBridge::SetOpenUrlDelegate(OpenUrlDelegate* delegate) {
- g_open_url_delegate = delegate;
- }
- // static
- void ArcIntentHelperBridge::SetControlCameraAppDelegate(
- ControlCameraAppDelegate* delegate) {
- g_control_camera_app_delegate = delegate;
- }
- void ArcIntentHelperBridge::SetDelegate(std::unique_ptr<Delegate> delegate) {
- delegate_ = std::move(delegate);
- }
- ArcIntentHelperBridge::ArcIntentHelperBridge(content::BrowserContext* context,
- ArcBridgeService* bridge_service)
- : context_(context),
- arc_bridge_service_(bridge_service),
- allowed_arc_schemes_(std::cbegin(kArcSchemes), std::cend(kArcSchemes)) {
- arc_bridge_service_->intent_helper()->SetHost(this);
- }
- ArcIntentHelperBridge::~ArcIntentHelperBridge() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- arc_bridge_service_->intent_helper()->SetHost(nullptr);
- }
- void ArcIntentHelperBridge::Shutdown() {
- for (auto& observer : observer_list_)
- observer.OnArcIntentHelperBridgeShutdown();
- }
- void ArcIntentHelperBridge::OnIconInvalidated(const std::string& package_name) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- icon_loader_.InvalidateIcons(package_name);
- for (auto& observer : observer_list_)
- observer.OnIconInvalidated(package_name);
- }
- void ArcIntentHelperBridge::OnIntentFiltersUpdated(
- std::vector<IntentFilter> filters) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- intent_filters_.clear();
- for (auto& filter : filters)
- intent_filters_[filter.package_name()].push_back(std::move(filter));
- for (auto& observer : observer_list_)
- observer.OnIntentFiltersUpdated(absl::nullopt);
- }
- void ArcIntentHelperBridge::OnOpenDownloads() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- RecordOpenType(ArcIntentHelperOpenType::DOWNLOADS);
- ash::NewWindowDelegate::GetInstance()->OpenDownloadsFolder();
- }
- void ArcIntentHelperBridge::OnOpenUrl(const std::string& url) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- RecordOpenType(ArcIntentHelperOpenType::URL);
- // Converts |url| to a fixed-up one and checks validity.
- const GURL gurl(url_formatter::FixupURL(url, /*desired_tld=*/std::string()));
- if (!gurl.is_valid())
- return;
- if (allowed_arc_schemes_.find(gurl.scheme()) != allowed_arc_schemes_.end())
- g_open_url_delegate->OpenUrlFromArc(gurl);
- }
- void ArcIntentHelperBridge::OnOpenCustomTab(const std::string& url,
- int32_t task_id,
- OnOpenCustomTabCallback callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- RecordOpenType(ArcIntentHelperOpenType::CUSTOM_TAB);
- // Converts |url| to a fixed-up one and checks validity.
- const GURL gurl(url_formatter::FixupURL(url, /*desired_tld=*/std::string()));
- if (!gurl.is_valid() ||
- allowed_arc_schemes_.find(gurl.scheme()) == allowed_arc_schemes_.end()) {
- std::move(callback).Run(mojo::NullRemote());
- return;
- }
- g_open_url_delegate->OpenArcCustomTab(gurl, task_id, std::move(callback));
- }
- void ArcIntentHelperBridge::OnOpenChromePage(mojom::ChromePage page) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- RecordOpenType(ArcIntentHelperOpenType::CHROME_PAGE);
- g_open_url_delegate->OpenChromePageFromArc(page);
- }
- void ArcIntentHelperBridge::FactoryResetArc() {
- if (delegate_)
- delegate_->ResetArc();
- }
- void ArcIntentHelperBridge::OpenWallpaperPicker() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- RecordOpenType(ArcIntentHelperOpenType::WALLPAPER_PICKER);
- ash::WallpaperController::Get()->OpenWallpaperPickerIfAllowed();
- }
- void ArcIntentHelperBridge::OpenVolumeControl() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- RecordOpenType(ArcIntentHelperOpenType::VOLUME_CONTROL);
- auto* audio = ArcAudioBridge::GetForBrowserContext(context_);
- DCHECK(audio);
- audio->ShowVolumeControls();
- }
- void ArcIntentHelperBridge::OnOpenWebApp(const std::string& url) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- RecordOpenType(ArcIntentHelperOpenType::WEB_APP);
- // Converts |url| to a fixed-up one and checks validity.
- const GURL gurl(url_formatter::FixupURL(url, /*desired_tld=*/std::string()));
- // Web app launches should only be invoked on HTTPS URLs.
- if (CanOpenWebAppForUrl(gurl))
- g_open_url_delegate->OpenWebAppFromArc(gurl);
- }
- // TODO(b/200873831): Delete this anytime on 2022.
- void ArcIntentHelperBridge::RecordShareFilesMetricsDeprecated(
- mojom::ShareFiles flag) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // Record metrics coming from ARC, these are related Share files feature
- // stability.
- LOG(ERROR) << "Arc.ShareFilesOnExit is deprecated, erasing incoming";
- }
- void ArcIntentHelperBridge::LaunchCameraApp(uint32_t intent_id,
- arc::mojom::CameraIntentMode mode,
- bool should_handle_result,
- bool should_down_scale,
- bool is_secure,
- int32_t task_id) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- std::string mode_str =
- mode == arc::mojom::CameraIntentMode::PHOTO ? "photo" : "video";
- std::stringstream queries;
- queries << "?intentId=" << intent_id << "&mode=" << mode_str
- << "&shouldHandleResult=" << should_handle_result
- << "&shouldDownScale=" << should_down_scale
- << "&isSecure=" << is_secure;
- g_control_camera_app_delegate->LaunchCameraApp(queries.str(), task_id);
- }
- void ArcIntentHelperBridge::OnIntentFiltersUpdatedForPackage(
- const std::string& package_name,
- std::vector<IntentFilter> filters) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- intent_filters_.erase(package_name);
- if (filters.size() > 0)
- intent_filters_[package_name] = std::move(filters);
- for (auto& observer : observer_list_)
- observer.OnIntentFiltersUpdated(package_name);
- }
- void ArcIntentHelperBridge::CloseCameraApp() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- g_control_camera_app_delegate->CloseCameraApp();
- }
- void ArcIntentHelperBridge::IsChromeAppEnabled(
- arc::mojom::ChromeApp app,
- IsChromeAppEnabledCallback callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (app == arc::mojom::ChromeApp::CAMERA) {
- std::move(callback).Run(
- g_control_camera_app_delegate->IsCameraAppEnabled());
- return;
- }
- NOTREACHED() << "Unknown chrome app";
- std::move(callback).Run(false);
- }
- void ArcIntentHelperBridge::OnSupportedLinksChanged(
- std::vector<arc::mojom::SupportedLinksPtr> added_packages,
- std::vector<arc::mojom::SupportedLinksPtr> removed_packages,
- arc::mojom::SupportedLinkChangeSource source) {
- for (auto& observer : observer_list_)
- observer.OnArcSupportedLinksChanged(added_packages, removed_packages,
- source);
- }
- void ArcIntentHelperBridge::OnDownloadAdded(
- const std::string& relative_path_as_string,
- const std::string& owner_package_name) {
- const base::FilePath download_folder("Download/");
- const base::FilePath relative_path(relative_path_as_string);
- // Observers should *not* be called when a download is added outside of the
- // Download/ folder. This would be an unexpected event coming from ARC but
- // we protect against it because ARC is treated as an untrusted source.
- if (!download_folder.IsParent(relative_path) ||
- relative_path.ReferencesParent()) {
- return;
- }
- for (auto& observer : observer_list_)
- observer.OnArcDownloadAdded(relative_path, owner_package_name);
- }
- void ArcIntentHelperBridge::OnOpenAppWithIntent(
- const GURL& start_url,
- arc::mojom::LaunchIntentPtr intent) {
- // Web app launches should only be invoked on HTTPS URLs.
- if (CanOpenWebAppForUrl(start_url)) {
- RecordOpenType(ArcIntentHelperOpenType::WEB_APP);
- RecordOpenAppIntentAction(intent);
- g_open_url_delegate->OpenAppWithIntent(start_url, std::move(intent));
- }
- }
- void ArcIntentHelperBridge::OnOpenGlobalActions() {
- ash::PowerButtonControllerBase::Get()->OnArcPowerButtonMenuEvent();
- }
- void ArcIntentHelperBridge::OnCloseSystemDialogs() {
- ash::PowerButtonControllerBase::Get()->CancelPowerButtonEvent();
- }
- ArcIntentHelperBridge::GetResult ArcIntentHelperBridge::GetActivityIcons(
- const std::vector<ActivityName>& activities,
- OnIconsReadyCallback callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return icon_loader_.GetActivityIcons(activities, std::move(callback));
- }
- void ArcIntentHelperBridge::SetAdaptiveIconDelegate(
- AdaptiveIconDelegate* delegate) {
- icon_loader_.SetAdaptiveIconDelegate(delegate);
- }
- void ArcIntentHelperBridge::AddObserver(ArcIntentHelperObserver* observer) {
- observer_list_.AddObserver(observer);
- }
- void ArcIntentHelperBridge::RemoveObserver(ArcIntentHelperObserver* observer) {
- observer_list_.RemoveObserver(observer);
- }
- bool ArcIntentHelperBridge::HasObserver(
- ArcIntentHelperObserver* observer) const {
- return observer_list_.HasObserver(observer);
- }
- void ArcIntentHelperBridge::HandleCameraResult(
- uint32_t intent_id,
- arc::mojom::CameraIntentAction action,
- const std::vector<uint8_t>& data,
- arc::mojom::IntentHelperInstance::HandleCameraResultCallback callback) {
- auto* arc_service_manager = arc::ArcServiceManager::Get();
- arc::mojom::IntentHelperInstance* instance = nullptr;
- if (arc_service_manager) {
- instance = ARC_GET_INSTANCE_FOR_METHOD(
- arc_service_manager->arc_bridge_service()->intent_helper(),
- HandleCameraResult);
- }
- if (!instance) {
- LOG(ERROR) << "Failed to get instance for HandleCameraResult().";
- std::move(callback).Run(false);
- return;
- }
- instance->HandleCameraResult(intent_id, action, data, std::move(callback));
- }
- void ArcIntentHelperBridge::SendNewCaptureBroadcast(bool is_video,
- std::string file_path) {
- auto* arc_service_manager = arc::ArcServiceManager::Get();
- arc::mojom::IntentHelperInstance* instance = nullptr;
- if (arc_service_manager) {
- instance = ARC_GET_INSTANCE_FOR_METHOD(
- arc_service_manager->arc_bridge_service()->intent_helper(),
- SendBroadcast);
- }
- if (!instance) {
- LOG(ERROR) << "Failed to get instance for SendBroadcast().";
- return;
- }
- std::string action =
- is_video ? "org.chromium.arc.intent_helper.ACTION_SEND_NEW_VIDEO"
- : "org.chromium.arc.intent_helper.ACTION_SEND_NEW_PICTURE";
- base::Value::Dict value;
- value.Set("file_path", file_path);
- std::string extras;
- base::JSONWriter::Write(value, &extras);
- instance->SendBroadcast(action, "org.chromium.arc.intent_helper",
- /*cls=*/std::string(), extras);
- }
- // static
- std::vector<mojom::IntentHandlerInfoPtr>
- ArcIntentHelperBridge::FilterOutIntentHelper(
- std::vector<mojom::IntentHandlerInfoPtr> handlers) {
- std::vector<mojom::IntentHandlerInfoPtr> handlers_filtered;
- for (auto& handler : handlers) {
- if (handler->package_name == kArcIntentHelperPackageName)
- continue;
- handlers_filtered.push_back(std::move(handler));
- }
- return handlers_filtered;
- }
- const std::vector<IntentFilter>&
- ArcIntentHelperBridge::GetIntentFilterForPackage(
- const std::string& package_name) {
- return intent_filters_[package_name];
- }
- } // namespace arc
|