From d18052357c22a365313e49f279cd313d663a7007 Mon Sep 17 00:00:00 2001 From: Maggie Cai Date: Thu, 29 Jul 2021 00:12:43 +0000 Subject: [PATCH] [Lacros] Create Lacros version AppServiceProxy. This CL splits up the code to have a dedicated AppServiceProxy for lacros-chrome. This is to prepare to make change of this newly created AppServiceProxy to talk with the app service in ash-chrome via crosapi instead of talk with the app service in lacros-chrome. This will be increamental changes to avoid large breakage of the tests and existing behaviours. BUG=1225827 Change-Id: Ieaa66452320e9bb31514eea5e19a024939789b41 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3058016 Reviewed-by: Dominick Ng Commit-Queue: Maggie Cai Cr-Commit-Position: refs/heads/master@{#906475} --- chrome/browser/BUILD.gn | 2 + .../apps/app_service/app_service_proxy.h | 2 + .../app_service/app_service_proxy_desktop.cc | 40 -- .../app_service/app_service_proxy_desktop.h | 19 - .../app_service/app_service_proxy_factory.h | 3 + .../app_service/app_service_proxy_lacros.cc | 628 ++++++++++++++++++ .../app_service/app_service_proxy_lacros.h | 373 +++++++++++ .../app_service/app_service_proxy_unittest.cc | 21 +- .../apps/app_service/app_service_test.h | 8 + .../browser/sharesheet/sharesheet_service.h | 8 + .../web_app_ui_manager_impl.cc | 14 +- .../web_apps_publisher_host_browsertest.cc | 2 +- .../system_web_app_manager_browsertest.cc | 4 + 13 files changed, 1045 insertions(+), 79 deletions(-) create mode 100644 chrome/browser/apps/app_service/app_service_proxy_lacros.cc create mode 100644 chrome/browser/apps/app_service/app_service_proxy_lacros.h diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 0341863512846..0ddad664c4b93 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn @@ -4788,6 +4788,8 @@ static_library("browser") { if (is_chromeos_lacros) { assert(enable_system_notifications) sources += [ + "apps/app_service/app_service_proxy_lacros.cc", + "apps/app_service/app_service_proxy_lacros.h", "apps/app_service/fake_lacros_web_apps_host.cc", "apps/app_service/fake_lacros_web_apps_host.h", "chrome_browser_main_parts_lacros.cc", diff --git a/chrome/browser/apps/app_service/app_service_proxy.h b/chrome/browser/apps/app_service/app_service_proxy.h index f405708eb0d91..fd329b32b5d7c 100644 --- a/chrome/browser/apps/app_service/app_service_proxy.h +++ b/chrome/browser/apps/app_service/app_service_proxy.h @@ -10,6 +10,8 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/apps/app_service/app_service_proxy_chromeos.h" +#elif BUILDFLAG(IS_CHROMEOS_LACROS) +#include "chrome/browser/apps/app_service/app_service_proxy_lacros.h" #else #include "chrome/browser/apps/app_service/app_service_proxy_desktop.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH) diff --git a/chrome/browser/apps/app_service/app_service_proxy_desktop.cc b/chrome/browser/apps/app_service/app_service_proxy_desktop.cc index 67ccc4b17d8f4..6a2aaf195459b 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_desktop.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_desktop.cc @@ -9,19 +9,8 @@ #include "chrome/browser/web_applications/web_app_provider.h" #include "components/services/app_service/app_service_impl.h" -#if BUILDFLAG(IS_CHROMEOS_LACROS) -#include "chrome/browser/apps/app_service/fake_lacros_web_apps_host.h" -#include "chrome/browser/web_applications/app_service/web_apps_publisher_host.h" -#endif - namespace apps { -#if BUILDFLAG(IS_CHROMEOS_LACROS) -// TODO(crbug.com/1144877): Remove after the actual lacros web app host code -// completed. -const bool kUseFakeWebAppsHost = false; -#endif - AppServiceProxy::AppServiceProxy(Profile* profile) : AppServiceProxyBase(profile) { Initialize(); @@ -43,20 +32,6 @@ void AppServiceProxy::Initialize() { web_apps_ = std::make_unique(app_service_, profile_); extension_apps_ = std::make_unique(app_service_, profile_); -#if BUILDFLAG(IS_CHROMEOS_LACROS) - if (kUseFakeWebAppsHost) { - // Create a fake lacros web app host in the lacros-chrome for testing lacros - // web app publishing. This will be removed after the actual lacros web app - // host code is created. - fake_lacros_web_apps_host_ = std::make_unique(); - fake_lacros_web_apps_host_->Init(); - } else { - web_apps_publisher_host_ = - std::make_unique(profile_); - web_apps_publisher_host_->Init(); - } -#endif - // Asynchronously add app icon source, so we don't do too much work in the // constructor. base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -81,24 +56,9 @@ void AppServiceProxy::FlushMojoCallsForTesting() { receivers_.FlushForTesting(); } -#if BUILDFLAG(IS_CHROMEOS_LACROS) -web_app::WebAppsPublisherHost* -AppServiceProxy::WebAppsPublisherHostForTesting() { - return web_apps_publisher_host_.get(); -} -#endif - bool AppServiceProxy::MaybeShowLaunchPreventionDialog( const apps::AppUpdate& update) { return false; } -void AppServiceProxy::Shutdown() { -#if BUILDFLAG(IS_CHROMEOS_LACROS) - if (web_apps_publisher_host_) { - web_apps_publisher_host_->Shutdown(); - } -#endif -} - } // namespace apps diff --git a/chrome/browser/apps/app_service/app_service_proxy_desktop.h b/chrome/browser/apps/app_service/app_service_proxy_desktop.h index c2078e1b42c0a..6a3240330fc97 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_desktop.h +++ b/chrome/browser/apps/app_service/app_service_proxy_desktop.h @@ -17,19 +17,12 @@ class Profile; namespace web_app { class WebApps; -#if BUILDFLAG(IS_CHROMEOS_LACROS) -class WebAppsPublisherHost; -#endif } // namespace web_app namespace apps { class ExtensionApps; -#if BUILDFLAG(IS_CHROMEOS_LACROS) -class FakeLacrosWebAppsHost; -#endif - // Singleton (per Profile) proxy and cache of an App Service's apps in Chrome // browser. // @@ -47,26 +40,14 @@ class AppServiceProxy : public AppServiceProxyBase { gfx::NativeWindow parent_window) override; void FlushMojoCallsForTesting() override; -#if BUILDFLAG(IS_CHROMEOS_LACROS) - web_app::WebAppsPublisherHost* WebAppsPublisherHostForTesting(); -#endif - private: // apps::AppServiceProxyBase overrides: void Initialize() override; bool MaybeShowLaunchPreventionDialog(const apps::AppUpdate& update) override; - // KeyedService overrides: - void Shutdown() override; - std::unique_ptr web_apps_; std::unique_ptr extension_apps_; -#if BUILDFLAG(IS_CHROMEOS_LACROS) - std::unique_ptr fake_lacros_web_apps_host_; - std::unique_ptr web_apps_publisher_host_; -#endif - base::WeakPtrFactory weak_ptr_factory_{this}; }; diff --git a/chrome/browser/apps/app_service/app_service_proxy_factory.h b/chrome/browser/apps/app_service/app_service_proxy_factory.h index 700c9a5b6d6ad..a8ae7863cd2cf 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_factory.h +++ b/chrome/browser/apps/app_service/app_service_proxy_factory.h @@ -15,6 +15,9 @@ namespace apps { #if BUILDFLAG(IS_CHROMEOS_ASH) class AppServiceProxyChromeOs; using AppServiceProxy = AppServiceProxyChromeOs; +#elif BUILDFLAG(IS_CHROMEOS_LACROS) +class AppServiceProxyLacros; +using AppServiceProxy = AppServiceProxyLacros; #else class AppServiceProxy; #endif diff --git a/chrome/browser/apps/app_service/app_service_proxy_lacros.cc b/chrome/browser/apps/app_service/app_service_proxy_lacros.cc new file mode 100644 index 0000000000000..387e1ed183762 --- /dev/null +++ b/chrome/browser/apps/app_service/app_service_proxy_lacros.cc @@ -0,0 +1,628 @@ +// Copyright 2021 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 "chrome/browser/apps/app_service/app_service_proxy_lacros.h" + +#include + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/containers/contains.h" +#include "base/debug/dump_without_crashing.h" +#include "base/feature_list.h" +#include "base/location.h" +#include "base/threading/thread_task_runner_handle.h" +#include "build/chromeos_buildflags.h" +#include "chrome/browser/apps/app_service/app_icon_source.h" +#include "chrome/browser/apps/app_service/app_service_metrics.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/fake_lacros_web_apps_host.h" +#include "chrome/browser/apps/app_service/launch_utils.h" +#include "chrome/browser/apps/app_service/publishers/extension_apps.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/app_service/web_apps.h" +#include "chrome/browser/web_applications/app_service/web_apps_publisher_host.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/common/chrome_features.h" +#include "components/services/app_service/app_service_impl.h" +#include "components/services/app_service/public/cpp/intent_filter_util.h" +#include "components/services/app_service/public/cpp/intent_util.h" +#include "components/services/app_service/public/cpp/types_util.h" +#include "components/services/app_service/public/mojom/types.mojom.h" +#include "content/public/browser/url_data_source.h" +#include "ui/display/types/display_constants.h" +#include "url/url_constants.h" + +namespace apps { + +const bool kUseFakeWebAppsHost = false; + +AppServiceProxyLacros::InnerIconLoader::InnerIconLoader( + AppServiceProxyLacros* host) + : host_(host), overriding_icon_loader_for_testing_(nullptr) {} + +apps::mojom::IconKeyPtr AppServiceProxyLacros::InnerIconLoader::GetIconKey( + const std::string& app_id) { + if (overriding_icon_loader_for_testing_) { + return overriding_icon_loader_for_testing_->GetIconKey(app_id); + } + + apps::mojom::IconKeyPtr icon_key; + if (host_->app_service_.is_connected()) { + host_->app_registry_cache_.ForOneApp( + app_id, [&icon_key](const apps::AppUpdate& update) { + icon_key = update.IconKey(); + }); + } + return icon_key; +} + +std::unique_ptr +AppServiceProxyLacros::InnerIconLoader::LoadIconFromIconKey( + apps::mojom::AppType app_type, + const std::string& app_id, + apps::mojom::IconKeyPtr icon_key, + apps::mojom::IconType icon_type, + int32_t size_hint_in_dip, + bool allow_placeholder_icon, + apps::mojom::Publisher::LoadIconCallback callback) { + if (overriding_icon_loader_for_testing_) { + return overriding_icon_loader_for_testing_->LoadIconFromIconKey( + app_type, app_id, std::move(icon_key), icon_type, size_hint_in_dip, + allow_placeholder_icon, std::move(callback)); + } + + if (host_->app_service_.is_connected() && icon_key) { + // TODO(crbug.com/826982): Mojo doesn't guarantee the order of messages, + // so multiple calls to this method might not resolve their callbacks in + // order. As per khmel@, "you may have race here, assume you publish change + // for the app and app requested new icon. But new icon is not delivered + // yet and you resolve old one instead. Now new icon arrives asynchronously + // but you no longer notify the app or do?" + host_->app_service_->LoadIcon(app_type, app_id, std::move(icon_key), + icon_type, size_hint_in_dip, + allow_placeholder_icon, std::move(callback)); + } else { + std::move(callback).Run(apps::mojom::IconValue::New()); + } + return nullptr; +} + +AppServiceProxyLacros::AppServiceProxyLacros(Profile* profile) + : inner_icon_loader_(this), + icon_coalescer_(&inner_icon_loader_), + outer_icon_loader_(&icon_coalescer_, + apps::IconCache::GarbageCollectionPolicy::kEager), + profile_(profile) { + Initialize(); +} + +AppServiceProxyLacros::~AppServiceProxyLacros() = default; + +void AppServiceProxyLacros::Initialize() { + if (!IsValidProfile()) { + return; + } + + browser_app_launcher_ = std::make_unique(profile_); + + app_service_impl_ = std::make_unique( + profile_->GetPath(), + base::FeatureList::IsEnabled(features::kIntentHandlingSharing)); + app_service_impl_->BindReceiver(app_service_.BindNewPipeAndPassReceiver()); + + if (app_service_.is_connected()) { + // The AppServiceProxy is a subscriber: something that wants to be able to + // list all known apps. + mojo::PendingRemote subscriber; + receivers_.Add(this, subscriber.InitWithNewPipeAndPassReceiver()); + app_service_->RegisterSubscriber(std::move(subscriber), nullptr); + } + + Observe(&app_registry_cache_); + + if (!app_service_.is_connected()) { + return; + } + + web_apps_ = std::make_unique(app_service_, profile_); + extension_apps_ = std::make_unique(app_service_, profile_); + + if (kUseFakeWebAppsHost) { + // Create a fake lacros web app host in the lacros-chrome for testing lacros + // web app publishing. This will be removed after the actual lacros web app + // host code is created. + fake_lacros_web_apps_host_ = std::make_unique(); + fake_lacros_web_apps_host_->Init(); + } else { + web_apps_publisher_host_ = + std::make_unique(profile_); + web_apps_publisher_host_->Init(); + } + + // Asynchronously add app icon source, so we don't do too much work in the + // constructor. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&AppServiceProxyLacros::AddAppIconSource, + weak_ptr_factory_.GetWeakPtr(), profile_)); +} + +void AppServiceProxyLacros::ReInitializeForTesting(Profile* profile) { + // Some test code creates a profile and profile-linked services, like the App + // Service, before the profile is fully initialized. Such tests can call this + // after full profile initialization to ensure the App Service implementation + // has all of profile state it needs. + app_service_.reset(); + profile_ = profile; + is_using_testing_profile_ = true; + Initialize(); +} + +bool AppServiceProxyLacros::IsValidProfile() { + if (!profile_) { + return false; + } + + // We only initialize the App Service for regular or guest profiles. Non-guest + // off-the-record profiles do not get an instance. + if (profile_->IsOffTheRecord() && !profile_->IsGuestSession()) { + return false; + } + + return true; +} + +mojo::Remote& AppServiceProxyLacros::AppService() { + return app_service_; +} + +apps::AppRegistryCache& AppServiceProxyLacros::AppRegistryCache() { + return app_registry_cache_; +} + +apps::AppCapabilityAccessCache& +AppServiceProxyLacros::AppCapabilityAccessCache() { + return app_capability_access_cache_; +} + +BrowserAppLauncher* AppServiceProxyLacros::BrowserAppLauncher() { + return browser_app_launcher_.get(); +} + +apps::PreferredAppsList& AppServiceProxyLacros::PreferredApps() { + return preferred_apps_; +} + +apps::mojom::IconKeyPtr AppServiceProxyLacros::GetIconKey( + const std::string& app_id) { + return outer_icon_loader_.GetIconKey(app_id); +} + +std::unique_ptr +AppServiceProxyLacros::LoadIconFromIconKey( + apps::mojom::AppType app_type, + const std::string& app_id, + apps::mojom::IconKeyPtr icon_key, + apps::mojom::IconType icon_type, + int32_t size_hint_in_dip, + bool allow_placeholder_icon, + apps::mojom::Publisher::LoadIconCallback callback) { + return outer_icon_loader_.LoadIconFromIconKey( + app_type, app_id, std::move(icon_key), icon_type, size_hint_in_dip, + allow_placeholder_icon, std::move(callback)); +} + +void AppServiceProxyLacros::Launch(const std::string& app_id, + int32_t event_flags, + apps::mojom::LaunchSource launch_source, + apps::mojom::WindowInfoPtr window_info) { + if (app_service_.is_connected()) { + app_registry_cache_.ForOneApp( + app_id, [this, event_flags, launch_source, + &window_info](const apps::AppUpdate& update) { + if (MaybeShowLaunchPreventionDialog(update)) { + return; + } + + RecordAppLaunch(update.AppId(), launch_source); + RecordAppPlatformMetrics( + profile_, update, launch_source, + apps::mojom::LaunchContainer::kLaunchContainerNone); + + app_service_->Launch(update.AppType(), update.AppId(), event_flags, + launch_source, std::move(window_info)); + }); + } +} + +void AppServiceProxyLacros::LaunchAppWithFiles( + const std::string& app_id, + apps::mojom::LaunchContainer container, + int32_t event_flags, + apps::mojom::LaunchSource launch_source, + apps::mojom::FilePathsPtr file_paths) { + if (app_service_.is_connected()) { + app_registry_cache_.ForOneApp( + app_id, [this, container, event_flags, launch_source, + &file_paths](const apps::AppUpdate& update) { + if (MaybeShowLaunchPreventionDialog(update)) { + return; + } + + RecordAppPlatformMetrics(profile_, update, launch_source, container); + + // TODO(crbug/1117655): File manager records metrics for apps it + // launched. So we only record launches from other places. We should + // eventually move those metrics here, after AppService supports all + // app types launched by file manager. + if (launch_source != apps::mojom::LaunchSource::kFromFileManager) { + RecordAppLaunch(update.AppId(), launch_source); + } + + app_service_->LaunchAppWithFiles( + update.AppType(), update.AppId(), container, event_flags, + launch_source, std::move(file_paths)); + }); + } +} + +void AppServiceProxyLacros::LaunchAppWithFileUrls( + const std::string& app_id, + int32_t event_flags, + apps::mojom::LaunchSource launch_source, + const std::vector& file_urls, + const std::vector& mime_types) { + LaunchAppWithIntent( + app_id, event_flags, + apps_util::CreateShareIntentFromFiles(file_urls, mime_types), + launch_source, MakeWindowInfo(display::kDefaultDisplayId)); +} + +void AppServiceProxyLacros::LaunchAppWithIntent( + const std::string& app_id, + int32_t event_flags, + apps::mojom::IntentPtr intent, + apps::mojom::LaunchSource launch_source, + apps::mojom::WindowInfoPtr window_info) { + CHECK(intent); + if (app_service_.is_connected()) { + app_registry_cache_.ForOneApp( + app_id, [this, event_flags, &intent, launch_source, + &window_info](const apps::AppUpdate& update) { + if (MaybeShowLaunchPreventionDialog(update)) { + return; + } + + RecordAppLaunch(update.AppId(), launch_source); + RecordAppPlatformMetrics( + profile_, update, launch_source, + apps::mojom::LaunchContainer::kLaunchContainerNone); + + app_service_->LaunchAppWithIntent( + update.AppType(), update.AppId(), event_flags, std::move(intent), + launch_source, std::move(window_info)); + }); + } +} + +void AppServiceProxyLacros::LaunchAppWithUrl( + const std::string& app_id, + int32_t event_flags, + GURL url, + apps::mojom::LaunchSource launch_source, + apps::mojom::WindowInfoPtr window_info) { + LaunchAppWithIntent(app_id, event_flags, apps_util::CreateIntentFromUrl(url), + launch_source, std::move(window_info)); +} + +void AppServiceProxyLacros::SetPermission( + const std::string& app_id, + apps::mojom::PermissionPtr permission) { + if (app_service_.is_connected()) { + app_registry_cache_.ForOneApp( + app_id, [this, &permission](const apps::AppUpdate& update) { + app_service_->SetPermission(update.AppType(), update.AppId(), + std::move(permission)); + }); + } +} + +void AppServiceProxyLacros::Uninstall( + const std::string& app_id, + apps::mojom::UninstallSource uninstall_source, + gfx::NativeWindow parent_window) { + // On non-ChromeOS, publishers run the remove dialog. + apps::mojom::AppType app_type = app_registry_cache_.GetAppType(app_id); + if (app_type == apps::mojom::AppType::kWeb) { + web_app::WebApps::UninstallImpl( + web_app::WebAppProvider::GetForWebApps(profile_), app_id, + uninstall_source, parent_window); + } +} + +void AppServiceProxyLacros::UninstallSilently( + const std::string& app_id, + apps::mojom::UninstallSource uninstall_source) { + if (app_service_.is_connected()) { + app_service_->Uninstall(app_registry_cache_.GetAppType(app_id), app_id, + uninstall_source, + /*clear_site_data=*/false, /*report_abuse=*/false); + } +} + +void AppServiceProxyLacros::StopApp(const std::string& app_id) { + if (!app_service_.is_connected()) { + return; + } + apps::mojom::AppType app_type = app_registry_cache_.GetAppType(app_id); + app_service_->StopApp(app_type, app_id); +} + +void AppServiceProxyLacros::GetMenuModel( + const std::string& app_id, + apps::mojom::MenuType menu_type, + int64_t display_id, + apps::mojom::Publisher::GetMenuModelCallback callback) { + if (!app_service_.is_connected()) { + return; + } + + apps::mojom::AppType app_type = app_registry_cache_.GetAppType(app_id); + app_service_->GetMenuModel(app_type, app_id, menu_type, display_id, + std::move(callback)); +} + +void AppServiceProxyLacros::ExecuteContextMenuCommand( + const std::string& app_id, + int command_id, + const std::string& shortcut_id, + int64_t display_id) { + if (!app_service_.is_connected()) { + return; + } + + apps::mojom::AppType app_type = app_registry_cache_.GetAppType(app_id); + app_service_->ExecuteContextMenuCommand(app_type, app_id, command_id, + shortcut_id, display_id); +} + +void AppServiceProxyLacros::OpenNativeSettings(const std::string& app_id) { + if (app_service_.is_connected()) { + app_registry_cache_.ForOneApp( + app_id, [this](const apps::AppUpdate& update) { + app_service_->OpenNativeSettings(update.AppType(), update.AppId()); + }); + } +} + +apps::IconLoader* AppServiceProxyLacros::OverrideInnerIconLoaderForTesting( + apps::IconLoader* icon_loader) { + apps::IconLoader* old = + inner_icon_loader_.overriding_icon_loader_for_testing_; + inner_icon_loader_.overriding_icon_loader_for_testing_ = icon_loader; + return old; +} + +std::vector AppServiceProxyLacros::GetAppIdsForUrl( + const GURL& url, + bool exclude_browsers, + bool exclude_browser_tab_apps) { + auto intent_launch_info = + GetAppsForIntent(apps_util::CreateIntentFromUrl(url), exclude_browsers, + exclude_browser_tab_apps); + std::vector app_ids; + for (auto& entry : intent_launch_info) { + app_ids.push_back(std::move(entry.app_id)); + } + return app_ids; +} + +std::vector AppServiceProxyLacros::GetAppsForIntent( + const apps::mojom::IntentPtr& intent, + bool exclude_browsers, + bool exclude_browser_tab_apps) { + std::vector intent_launch_info; + if (apps_util::OnlyShareToDrive(intent) || + !apps_util::IsIntentValid(intent)) { + return intent_launch_info; + } + + if (app_service_.is_bound()) { + app_registry_cache_.ForEachApp( + [&intent_launch_info, &intent, &exclude_browsers, + &exclude_browser_tab_apps](const apps::AppUpdate& update) { + if (!apps_util::IsInstalled(update.Readiness()) || + update.ShowInLauncher() != apps::mojom::OptionalBool::kTrue) { + return; + } + if (exclude_browser_tab_apps && + update.WindowMode() == mojom::WindowMode::kBrowser) { + return; + } + std::set existing_activities; + for (const auto& filter : update.IntentFilters()) { + if (exclude_browsers && apps_util::IsBrowserFilter(filter)) { + continue; + } + if (apps_util::IntentMatchesFilter(intent, filter)) { + IntentLaunchInfo entry; + entry.app_id = update.AppId(); + std::string activity_label; + if (filter->activity_label && + !filter->activity_label.value().empty()) { + activity_label = filter->activity_label.value(); + } else { + activity_label = update.Name(); + } + if (base::Contains(existing_activities, activity_label)) { + continue; + } + existing_activities.insert(activity_label); + entry.activity_label = activity_label; + entry.activity_name = filter->activity_name.value_or(""); + intent_launch_info.push_back(entry); + } + } + }); + } + return intent_launch_info; +} + +std::vector AppServiceProxyLacros::GetAppsForFiles( + const std::vector& filesystem_urls, + const std::vector& mime_types) { + return GetAppsForIntent( + apps_util::CreateShareIntentFromFiles(filesystem_urls, mime_types)); +} + +void AppServiceProxyLacros::AddPreferredApp(const std::string& app_id, + const GURL& url) { + AddPreferredApp(app_id, apps_util::CreateIntentFromUrl(url)); +} + +void AppServiceProxyLacros::AddPreferredApp( + const std::string& app_id, + const apps::mojom::IntentPtr& intent) { + // TODO(https://crbug.com/853604): Remove this and convert to a DCHECK + // after finding out the root cause. + if (app_id.empty()) { + base::debug::DumpWithoutCrashing(); + return; + } + auto intent_filter = FindBestMatchingFilter(intent); + if (!intent_filter) { + return; + } + preferred_apps_.AddPreferredApp(app_id, intent_filter); + if (app_service_.is_connected()) { + constexpr bool kFromPublisher = false; + app_service_->AddPreferredApp(app_registry_cache_.GetAppType(app_id), + app_id, std::move(intent_filter), + intent->Clone(), kFromPublisher); + } +} + +void AppServiceProxyLacros::SetWindowMode(const std::string& app_id, + apps::mojom::WindowMode window_mode) { + if (app_service_.is_connected()) { + app_service_->SetWindowMode(app_registry_cache_.GetAppType(app_id), app_id, + window_mode); + } +} + +void AppServiceProxyLacros::AddAppIconSource(Profile* profile) { + // Make the chrome://app-icon/ resource available. + content::URLDataSource::Add(profile, + std::make_unique(profile)); +} + +void AppServiceProxyLacros::OnApps(std::vector deltas, + apps::mojom::AppType app_type, + bool should_notify_initialized) { + if (app_service_.is_connected()) { + for (const auto& delta : deltas) { + if (!apps_util::IsInstalled(delta->readiness)) { + app_service_->RemovePreferredApp(delta->app_type, delta->app_id); + } + } + } + + app_registry_cache_.OnApps(std::move(deltas), app_type, + should_notify_initialized); +} + +void AppServiceProxyLacros::OnCapabilityAccesses( + std::vector deltas) { + app_capability_access_cache_.OnCapabilityAccesses(std::move(deltas)); +} + +void AppServiceProxyLacros::Clone( + mojo::PendingReceiver receiver) { + receivers_.Add(this, std::move(receiver)); +} + +void AppServiceProxyLacros::OnPreferredAppSet( + const std::string& app_id, + apps::mojom::IntentFilterPtr intent_filter) { + preferred_apps_.AddPreferredApp(app_id, intent_filter); +} + +void AppServiceProxyLacros::OnPreferredAppRemoved( + const std::string& app_id, + apps::mojom::IntentFilterPtr intent_filter) { + preferred_apps_.DeletePreferredApp(app_id, intent_filter); +} + +void AppServiceProxyLacros::InitializePreferredApps( + PreferredAppsList::PreferredApps preferred_apps) { + preferred_apps_.Init(preferred_apps); +} + +void AppServiceProxyLacros::OnAppUpdate(const apps::AppUpdate& update) { + if (!update.ReadinessChanged() || + !apps_util::IsInstalled(update.Readiness())) { + return; + } + preferred_apps_.DeleteAppId(update.AppId()); +} + +void AppServiceProxyLacros::OnAppRegistryCacheWillBeDestroyed( + apps::AppRegistryCache* cache) { + Observe(nullptr); +} + +apps::mojom::IntentFilterPtr AppServiceProxyLacros::FindBestMatchingFilter( + const apps::mojom::IntentPtr& intent) { + apps::mojom::IntentFilterPtr best_matching_intent_filter; + if (!app_service_.is_bound()) { + return best_matching_intent_filter; + } + + int best_match_level = apps_util::IntentFilterMatchLevel::kNone; + app_registry_cache_.ForEachApp( + [&intent, &best_match_level, + &best_matching_intent_filter](const apps::AppUpdate& update) { + for (const auto& filter : update.IntentFilters()) { + if (!apps_util::IntentMatchesFilter(intent, filter)) { + continue; + } + auto match_level = apps_util::GetFilterMatchLevel(filter); + if (match_level <= best_match_level) { + continue; + } + best_matching_intent_filter = filter->Clone(); + best_match_level = match_level; + } + }); + return best_matching_intent_filter; +} + +void AppServiceProxyLacros::RecordAppPlatformMetrics( + Profile* profile, + const apps::AppUpdate& update, + apps::mojom::LaunchSource launch_source, + apps::mojom::LaunchContainer container) {} + +void AppServiceProxyLacros::FlushMojoCallsForTesting() { + app_service_impl_->FlushMojoCallsForTesting(); + receivers_.FlushForTesting(); +} + +web_app::WebAppsPublisherHost* +AppServiceProxyLacros::WebAppsPublisherHostForTesting() { + return web_apps_publisher_host_.get(); +} + +bool AppServiceProxyLacros::MaybeShowLaunchPreventionDialog( + const apps::AppUpdate& update) { + return false; +} + +void AppServiceProxyLacros::Shutdown() { + if (web_apps_publisher_host_) { + web_apps_publisher_host_->Shutdown(); + } +} + +} // namespace apps diff --git a/chrome/browser/apps/app_service/app_service_proxy_lacros.h b/chrome/browser/apps/app_service/app_service_proxy_lacros.h new file mode 100644 index 0000000000000..ab905c8cabd47 --- /dev/null +++ b/chrome/browser/apps/app_service/app_service_proxy_lacros.h @@ -0,0 +1,373 @@ +// Copyright 2021 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. + +#ifndef CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_LACROS_H_ +#define CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_LACROS_H_ + +#include +#include +#include + +#include "base/callback.h" +#include "base/containers/unique_ptr_adapters.h" +#include "base/memory/weak_ptr.h" +#include "build/chromeos_buildflags.h" +#include "chrome/browser/apps/app_service/browser_app_launcher.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/services/app_service/public/cpp/app_capability_access_cache.h" +#include "components/services/app_service/public/cpp/app_registry_cache.h" +#include "components/services/app_service/public/cpp/icon_cache.h" +#include "components/services/app_service/public/cpp/icon_coalescer.h" +#include "components/services/app_service/public/cpp/preferred_apps_list.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "ui/gfx/native_widget_types.h" +#include "url/gurl.h" + +class Profile; + +namespace web_app { +class WebApps; +class WebAppsPublisherHost; +} // namespace web_app + +namespace apps { + +class AppServiceImpl; +class ExtensionApps; +class FakeLacrosWebAppsHost; + +struct IntentLaunchInfo { + std::string app_id; + std::string activity_name; + std::string activity_label; +}; + +// Singleton (per Profile) proxy and cache of an App Service's apps. +// +// Singleton-ness means that //chrome/browser code (e.g UI code) can find *the* +// proxy for a given Profile, and therefore share its caches. +// Observe AppRegistryCache to delete the preferred app on app removed. +// +// On all platforms, there is no instance for incognito profiles. +// On Chrome OS, an instance is created for the guest session profile and the +// lock screen apps profile, but not for the signin profile. +// +// See components/services/app_service/README.md. +class AppServiceProxyLacros : public KeyedService, + public apps::IconLoader, + public apps::mojom::Subscriber, + public apps::AppRegistryCache::Observer { + public: + explicit AppServiceProxyLacros(Profile* profile); + AppServiceProxyLacros(const AppServiceProxyLacros&) = delete; + AppServiceProxyLacros& operator=(const AppServiceProxyLacros&) = delete; + ~AppServiceProxyLacros() override; + + void ReInitializeForTesting(Profile* profile); + + mojo::Remote& AppService(); + apps::AppRegistryCache& AppRegistryCache(); + apps::AppCapabilityAccessCache& AppCapabilityAccessCache(); + + apps::BrowserAppLauncher* BrowserAppLauncher(); + + apps::PreferredAppsList& PreferredApps(); + + // apps::IconLoader overrides. + apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override; + std::unique_ptr LoadIconFromIconKey( + apps::mojom::AppType app_type, + const std::string& app_id, + apps::mojom::IconKeyPtr icon_key, + apps::mojom::IconType icon_type, + int32_t size_hint_in_dip, + bool allow_placeholder_icon, + apps::mojom::Publisher::LoadIconCallback callback) override; + + // Launches the app for the given |app_id|. |event_flags| provides additional + // context about the action which launches the app (e.g. a middle click + // indicating opening a background tab). |launch_source| is the possible app + // launch sources, e.g. from Shelf, from the search box, etc. |window_info| is + // the window information to launch an app, e.g. display_id, window bounds. + // + // Note: prefer using LaunchSystemWebAppAsync() for launching System Web Apps, + // as that is robust to the choice of profile and avoids needing to specify an + // app_id. + void Launch(const std::string& app_id, + int32_t event_flags, + apps::mojom::LaunchSource launch_source, + apps::mojom::WindowInfoPtr window_info = nullptr); + + // Launches the app for the given |app_id| with files from |file_paths|. + // |event_flags| provides additional context about the action which launches + // the app (e.g. a middle click indicating opening a background tab). + // |launch_source| is the possible app launch sources, e.g. from Shelf, from + // the search box, etc. + void LaunchAppWithFiles(const std::string& app_id, + apps::mojom::LaunchContainer container, + int32_t event_flags, + apps::mojom::LaunchSource launch_source, + apps::mojom::FilePathsPtr file_paths); + + // Launches the app for the given |app_id| with files from |file_urls| and + // their |mime_types|. + // |event_flags| provides additional context about the action which launches + // the app (e.g. a middle click indicating opening a background tab). + // |launch_source| is the possible app launch sources, e.g. from Shelf, from + // the search box, etc. + void LaunchAppWithFileUrls(const std::string& app_id, + int32_t event_flags, + apps::mojom::LaunchSource launch_source, + const std::vector& file_urls, + const std::vector& mime_types); + + // Launches an app for the given |app_id|, passing |intent| to the app. + // |event_flags| provides additional context about the action which launch the + // app (e.g. a middle click indicating opening a background tab). + // |launch_source| is the possible app launch sources. |window_info| is the + // window information to launch an app, e.g. display_id, window bounds. + void LaunchAppWithIntent(const std::string& app_id, + int32_t event_flags, + apps::mojom::IntentPtr intent, + apps::mojom::LaunchSource launch_source, + apps::mojom::WindowInfoPtr window_info = nullptr); + + // Launches an app for the given |app_id|, passing |url| to the app. + // |event_flags| provides additional context about the action which launch the + // app (e.g. a middle click indicating opening a background tab). + // |launch_source| is the possible app launch sources. |window_info| is the + // window information to launch an app, e.g. display_id, window bounds. + void LaunchAppWithUrl(const std::string& app_id, + int32_t event_flags, + GURL url, + apps::mojom::LaunchSource launch_source, + apps::mojom::WindowInfoPtr window_info = nullptr); + + // Sets |permission| for the app identified by |app_id|. + void SetPermission(const std::string& app_id, + apps::mojom::PermissionPtr permission); + + // Uninstalls an app for the given |app_id|. If |parent_window| is specified, + // the uninstall dialog will be created as a modal dialog anchored at + // |parent_window|. Otherwise, the browser window will be used as the anchor. + void Uninstall(const std::string& app_id, + apps::mojom::UninstallSource uninstall_source, + gfx::NativeWindow parent_window); + + // Uninstalls an app for the given |app_id| without prompting the user to + // confirm. + void UninstallSilently(const std::string& app_id, + apps::mojom::UninstallSource uninstall_source); + + // Stops the current running app for the given |app_id|. + void StopApp(const std::string& app_id); + + // Returns the menu items for the given |app_id|. |display_id| is the id of + // the display from which the app is launched. + void GetMenuModel(const std::string& app_id, + apps::mojom::MenuType menu_type, + int64_t display_id, + apps::mojom::Publisher::GetMenuModelCallback callback); + + // Executes a shortcut menu |command_id| and |shortcut_id| for a menu item + // previously built with GetMenuModel(). |app_id| is the menu app. + // |display_id| is the id of the display from which the app is launched. + void ExecuteContextMenuCommand(const std::string& app_id, + int command_id, + const std::string& shortcut_id, + int64_t display_id); + + // Opens native settings for the app with |app_id|. + void OpenNativeSettings(const std::string& app_id); + + void FlushMojoCallsForTesting(); + + apps::IconLoader* OverrideInnerIconLoaderForTesting( + apps::IconLoader* icon_loader); + + // Returns a list of apps (represented by their ids) which can handle |url|. + // If |exclude_browsers| is true, then exclude the browser apps. + // If |exclude_browser_tab_apps| is true then exclude apps that open in + // browser tabs. + std::vector GetAppIdsForUrl( + const GURL& url, + bool exclude_browsers = false, + bool exclude_browser_tab_apps = true); + + // Returns a list of apps (represented by their ids) and activities (if + // applied) which can handle |intent|. If |exclude_browsers| is true, then + // exclude the browser apps. If |exclude_browser_tab_apps| is true then + // exclude apps that open in browser tabs. + std::vector GetAppsForIntent( + const apps::mojom::IntentPtr& intent, + bool exclude_browsers = false, + bool exclude_browser_tab_apps = true); + + // Returns a list of apps (represented by their ids) and activities (if + // applied) which can handle |filesystem_urls| and |mime_types|. + std::vector GetAppsForFiles( + const std::vector& filesystem_urls, + const std::vector& mime_types); + + // Adds a preferred app for |url|. + void AddPreferredApp(const std::string& app_id, const GURL& url); + // Adds a preferred app for |intent|. + void AddPreferredApp(const std::string& app_id, + const apps::mojom::IntentPtr& intent); + + void SetWindowMode(const std::string& app_id, + apps::mojom::WindowMode window_mode); + + web_app::WebAppsPublisherHost* WebAppsPublisherHostForTesting(); + + protected: + // An adapter, presenting an IconLoader interface based on the underlying + // Mojo service (or on a fake implementation for testing). + // + // Conceptually, the ASP (the AppServiceProxyLacros) is itself such an + // adapter: UI clients call the IconLoader::LoadIconFromIconKey method (which + // the ASP implements) and the ASP translates (i.e. adapts) these to Mojo + // calls (or C++ calls to the Fake). This diagram shows control flow going + // left to right (with "=c=>" and "=m=>" denoting C++ and Mojo calls), and the + // responses (callbacks) then run right to left in LIFO order: + // + // UI =c=> ASP =+=m=> MojoService + // | or + // +=c=> Fake + // + // It is more complicated in practice, as we want to insert IconLoader + // decorators (as in the classic "decorator" or "wrapper" design pattern) to + // provide optimizations like proxy-wide icon caching and IPC coalescing + // (de-duplication). Nonetheless, from a UI client's point of view, we would + // still like to present a simple API: that the ASP implements the IconLoader + // interface. We therefore split the "ASP" component into multiple + // sub-components. Once again, control flow runs from left to right, and + // inside the ASP, outer layers (wrappers) call into inner layers (wrappees): + // + // +------------------ ASP ------------------+ + // | | + // UI =c=> | Outer =c=> MoreDecorators... =c=> Inner | =+=m=> MojoService + // | | | or + // +-----------------------------------------+ +=c=> Fake + // + // The inner_icon_loader_ field (of type InnerIconLoader) is the "Inner" + // component: the one that ultimately talks to the Mojo service. + // + // The outer_icon_loader_ field (of type IconCache) is the "Outer" component: + // the entry point for calls into the AppServiceProxyLacros. + // + // Note that even if the ASP provides some icon caching, upstream UI clients + // may want to introduce further icon caching. See the commentary where + // IconCache::GarbageCollectionPolicy is defined. + // + // IPC coalescing would be one of the "MoreDecorators". + class InnerIconLoader : public apps::IconLoader { + public: + explicit InnerIconLoader(AppServiceProxyLacros* host); + + // apps::IconLoader overrides. + apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override; + std::unique_ptr LoadIconFromIconKey( + apps::mojom::AppType app_type, + const std::string& app_id, + apps::mojom::IconKeyPtr icon_key, + apps::mojom::IconType icon_type, + int32_t size_hint_in_dip, + bool allow_placeholder_icon, + apps::mojom::Publisher::LoadIconCallback callback) override; + + // |host_| owns |this|, as the InnerIconLoader is an AppServiceProxyLacros + // field. + AppServiceProxyLacros* host_; + + apps::IconLoader* overriding_icon_loader_for_testing_; + }; + + bool IsValidProfile(); + + void Initialize(); + + void AddAppIconSource(Profile* profile); + + // Returns true if the app cannot be launched and a launch prevention dialog + // is shown to the user (e.g. the app is paused or blocked). Returns false + // otherwise (and the app can be launched). + bool MaybeShowLaunchPreventionDialog(const apps::AppUpdate& update); + + // KeyedService overrides: + void Shutdown() override; + + // apps::mojom::Subscriber overrides. + void OnApps(std::vector deltas, + apps::mojom::AppType app_type, + bool should_notify_initialized) override; + void OnCapabilityAccesses( + std::vector deltas) override; + void Clone(mojo::PendingReceiver receiver) override; + void OnPreferredAppSet(const std::string& app_id, + apps::mojom::IntentFilterPtr intent_filter) override; + void OnPreferredAppRemoved( + const std::string& app_id, + apps::mojom::IntentFilterPtr intent_filter) override; + void InitializePreferredApps( + PreferredAppsList::PreferredApps preferred_apps) override; + + // apps::AppRegistryCache::Observer overrides: + void OnAppUpdate(const apps::AppUpdate& update) override; + void OnAppRegistryCacheWillBeDestroyed( + apps::AppRegistryCache* cache) override; + + apps::mojom::IntentFilterPtr FindBestMatchingFilter( + const apps::mojom::IntentPtr& intent); + + virtual void RecordAppPlatformMetrics(Profile* profile, + const apps::AppUpdate& update, + apps::mojom::LaunchSource launch_source, + apps::mojom::LaunchContainer container); + + // This proxy privately owns its instance of the App Service. This should not + // be exposed except through the Mojo interface connected to |app_service_|. + std::unique_ptr app_service_impl_; + + mojo::Remote app_service_; + apps::AppRegistryCache app_registry_cache_; + apps::AppCapabilityAccessCache app_capability_access_cache_; + + mojo::ReceiverSet receivers_; + + // The LoadIconFromIconKey implementation sends a chained series of requests + // through each icon loader, starting from the outer and working back to the + // inner. Fields are listed from inner to outer, the opposite of call order, + // as each one depends on the previous one, and in the constructor, + // initialization happens in field order. + InnerIconLoader inner_icon_loader_; + IconCoalescer icon_coalescer_; + IconCache outer_icon_loader_; + + apps::PreferredAppsList preferred_apps_; + + Profile* profile_; + + // TODO(crbug.com/1061843): Remove BrowserAppLauncher and merge the interfaces + // to AppServiceProxyLacros when publishers(ExtensionApps and WebApps) can run + // on Chrome. + std::unique_ptr browser_app_launcher_; + + bool is_using_testing_profile_ = false; + base::OnceClosure dialog_created_callback_; + + std::unique_ptr web_apps_; + std::unique_ptr extension_apps_; + + std::unique_ptr fake_lacros_web_apps_host_; + std::unique_ptr web_apps_publisher_host_; + + base::WeakPtrFactory weak_ptr_factory_{this}; +}; + +} // namespace apps + +#endif // CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_LACROS_H_ diff --git a/chrome/browser/apps/app_service/app_service_proxy_unittest.cc b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc index 0695eb0e830f9..5b0b5b2d4bb75 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_unittest.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc @@ -18,6 +18,13 @@ class AppServiceProxyTest : public testing::Test { protected: using UniqueReleaser = std::unique_ptr; +#if BUILDFLAG(IS_CHROMEOS_ASH) + using AppServiceProxy = apps::AppServiceProxyChromeOs; +#elif BUILDFLAG(IS_CHROMEOS_LACROS) + using AppServiceProxy = apps::AppServiceProxyLacros; +#else + using AppServiceProxy = apps::AppServiceProxy; +#endif class FakeIconLoader : public apps::IconLoader { public: @@ -73,7 +80,7 @@ class AppServiceProxyTest : public testing::Test { base::Unretained(this))); } - void OverrideAppServiceProxyInnerIconLoader(apps::AppServiceProxyBase* proxy, + void OverrideAppServiceProxyInnerIconLoader(AppServiceProxy* proxy, apps::IconLoader* icon_loader) { proxy->OverrideInnerIconLoaderForTesting(icon_loader); } @@ -96,11 +103,7 @@ TEST_F(AppServiceProxyTest, IconCache) { // This tests an AppServiceProxy as a 'black box', which uses an // IconCache but also other IconLoader filters, such as an IconCoalescer. -#if BUILDFLAG(IS_CHROMEOS_ASH) - apps::AppServiceProxyChromeOs proxy(nullptr); -#else - apps::AppServiceProxy proxy(nullptr); -#endif + AppServiceProxy proxy(nullptr); FakeIconLoader fake; OverrideAppServiceProxyInnerIconLoader(&proxy, &fake); @@ -146,11 +149,7 @@ TEST_F(AppServiceProxyTest, IconCoalescer) { // This tests an AppServiceProxy as a 'black box', which uses an // IconCoalescer but also other IconLoader filters, such as an IconCache. -#if BUILDFLAG(IS_CHROMEOS_ASH) - apps::AppServiceProxyChromeOs proxy(nullptr); -#else - apps::AppServiceProxy proxy(nullptr); -#endif + AppServiceProxy proxy(nullptr); FakeIconLoader fake; OverrideAppServiceProxyInnerIconLoader(&proxy, &fake); diff --git a/chrome/browser/apps/app_service/app_service_test.h b/chrome/browser/apps/app_service/app_service_test.h index 13aa13e0961d4..287708c896e75 100644 --- a/chrome/browser/apps/app_service/app_service_test.h +++ b/chrome/browser/apps/app_service/app_service_test.h @@ -16,7 +16,11 @@ class Profile; namespace apps { +#if BUILDFLAG(IS_CHROMEOS_LACROS) +class AppServiceProxyLacros; +#else class AppServiceProxyBase; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) // Helper class to initialize AppService in unit tests. class AppServiceTest { @@ -47,7 +51,11 @@ class AppServiceTest { void FlushMojoCalls(); private: +#if BUILDFLAG(IS_CHROMEOS_LACROS) + AppServiceProxyLacros* app_service_proxy_ = nullptr; +#else AppServiceProxyBase* app_service_proxy_ = nullptr; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) Profile* profile_ = nullptr; }; diff --git a/chrome/browser/sharesheet/sharesheet_service.h b/chrome/browser/sharesheet/sharesheet_service.h index 941020b5c39a5..5787d81c33450 100644 --- a/chrome/browser/sharesheet/sharesheet_service.h +++ b/chrome/browser/sharesheet/sharesheet_service.h @@ -23,7 +23,11 @@ class Profile; namespace apps { struct IntentLaunchInfo; +#if BUILDFLAG(IS_CHROMEOS_LACROS) +class AppServiceProxyLacros; +#else class AppServiceProxyBase; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) } // namespace apps namespace views { @@ -147,7 +151,11 @@ class SharesheetService : public KeyedService { Profile* profile_; std::unique_ptr sharesheet_action_cache_; +#if BUILDFLAG(IS_CHROMEOS_LACROS) + apps::AppServiceProxyLacros* app_service_proxy_; +#else apps::AppServiceProxyBase* app_service_proxy_; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) // Record of all active SharesheetServiceDelegates. These can be retrieved // by ShareActions and used as SharesheetControllers to make bubble changes. diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc index 1579ed95ff6e9..cac99000d20c5 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc @@ -55,8 +55,9 @@ namespace web_app { namespace { -bool IsAppInstalled(apps::AppServiceProxyBase* proxy, const AppId& app_id) { +bool IsAppInstalled(Profile* profile, const AppId& app_id) { bool installed = false; + auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile); proxy->AppRegistryCache().ForOneApp( app_id, [&installed](const apps::AppUpdate& update) { installed = apps_util::IsInstalled(update.Readiness()); @@ -178,9 +179,7 @@ bool WebAppUiManagerImpl::UninstallAndReplaceIfExists( bool has_migrated = false; bool uninstall_triggered = false; for (const AppId& from_app : from_apps) { - apps::AppServiceProxyBase* proxy = - apps::AppServiceProxyFactory::GetForProfile(profile_); - if (!IsAppInstalled(proxy, from_app)) + if (!IsAppInstalled(profile_, from_app)) continue; if (!has_migrated) { @@ -245,6 +244,7 @@ bool WebAppUiManagerImpl::UninstallAndReplaceIfExists( continue; } + auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile_); proxy->UninstallSilently(from_app, apps::mojom::UninstallSource::kMigration); uninstall_triggered = true; @@ -265,8 +265,7 @@ void WebAppUiManagerImpl::OnShortcutInfoReceivedSearchShortcutLocations( std::unique_ptr shortcut_info) { if (!shortcut_info) { // The shortcut info couldn't be found, simply uninstall. - apps::AppServiceProxyBase* proxy = - apps::AppServiceProxyFactory::GetForProfile(profile_); + auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile_); proxy->UninstallSilently(from_app, apps::mojom::UninstallSource::kMigration); return; @@ -282,8 +281,7 @@ void WebAppUiManagerImpl::OnShortcutLocationGathered( const AppId& from_app, const AppId& app_id, ShortcutLocations locations) { - apps::AppServiceProxyBase* proxy = - apps::AppServiceProxyFactory::GetForProfile(profile_); + auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile_); const bool is_extension = proxy->AppRegistryCache().GetAppType(from_app) == apps::mojom::AppType::kExtension; diff --git a/chrome/browser/web_applications/app_service/web_apps_publisher_host_browsertest.cc b/chrome/browser/web_applications/app_service/web_apps_publisher_host_browsertest.cc index e2202ec1363d9..23ceacf2d928a 100644 --- a/chrome/browser/web_applications/app_service/web_apps_publisher_host_browsertest.cc +++ b/chrome/browser/web_applications/app_service/web_apps_publisher_host_browsertest.cc @@ -20,7 +20,7 @@ #include "base/test/scoped_feature_list.h" #include "base/values.h" #include "chrome/browser/apps/app_service/app_icon_factory.h" -#include "chrome/browser/apps/app_service/app_service_proxy_desktop.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc index c13ce178c1dd3..05803c7b7e61e 100644 --- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc +++ b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc @@ -78,7 +78,11 @@ namespace { // Helper to call AppServiceProxyFactory::GetForProfile(). +#if BUILDFLAG(IS_CHROMEOS_LACROS) +apps::AppServiceProxyLacros* GetAppServiceProxy(Profile* profile) { +#else apps::AppServiceProxyBase* GetAppServiceProxy(Profile* profile) { +#endif // Crash if there is no AppService support for |profile|. GetForProfile() will // DumpWithoutCrashing, which will not fail a test. No codepath should trigger // that in normal operation.