| // Copyright 2021 The Chromium Authors |
| // 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_BASE_H_ |
| #define CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_BASE_H_ |
| |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <optional> |
| #include <ostream> |
| #include <string> |
| #include <vector> |
| |
| #include "base/containers/flat_map.h" |
| #include "base/functional/callback.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "chrome/browser/apps/app_service/app_launch_params.h" |
| #include "chrome/browser/apps/app_service/launch_result_type.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_launch_util.h" |
| #include "components/services/app_service/public/cpp/app_registry_cache.h" |
| #include "components/services/app_service/public/cpp/app_types.h" |
| #include "components/services/app_service/public/cpp/capability_access.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/icon_loader.h" |
| #include "components/services/app_service/public/cpp/icon_types.h" |
| #include "components/services/app_service/public/cpp/intent.h" |
| #include "components/services/app_service/public/cpp/intent_filter.h" |
| #include "components/services/app_service/public/cpp/menu.h" |
| #include "components/services/app_service/public/cpp/permission.h" |
| #include "components/services/app_service/public/cpp/preferred_app.h" |
| #include "components/services/app_service/public/cpp/preferred_apps_impl.h" |
| #include "ui/gfx/native_widget_types.h" |
| |
| class Profile; |
| class GURL; |
| |
| namespace base { |
| class FilePath; |
| } |
| |
| namespace apps { |
| |
| class AppPublisher; |
| class AppUpdate; |
| class BrowserAppLauncher; |
| class PreferredAppsListHandle; |
| |
| struct IntentLaunchInfo { |
| IntentLaunchInfo(); |
| ~IntentLaunchInfo(); |
| IntentLaunchInfo(const IntentLaunchInfo& other); |
| |
| std::string app_id; |
| std::string activity_name; |
| std::string activity_label; |
| bool is_generic_file_handler; |
| bool is_file_extension_match; |
| // Whether the intent is blocked by DLP. Defaults to false. |
| bool is_dlp_blocked = false; |
| }; |
| |
| // 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 AppServiceProxyBase : public KeyedService, |
| public PreferredAppsImpl::Host { |
| public: |
| explicit AppServiceProxyBase(Profile* profile); |
| AppServiceProxyBase(const AppServiceProxyBase&) = delete; |
| AppServiceProxyBase& operator=(const AppServiceProxyBase&) = delete; |
| ~AppServiceProxyBase() override; |
| |
| void ReinitializeForTesting( |
| Profile* profile, |
| base::OnceClosure read_completed_for_testing = base::OnceClosure(), |
| base::OnceClosure write_completed_for_testing = base::OnceClosure()); |
| |
| Profile* profile() const { return profile_; } |
| |
| apps::AppRegistryCache& AppRegistryCache(); |
| apps::AppCapabilityAccessCache& AppCapabilityAccessCache(); |
| |
| apps::BrowserAppLauncher* BrowserAppLauncher(); |
| |
| apps::PreferredAppsListHandle& PreferredAppsList(); |
| |
| // Registers `publisher` with the App Service as exclusively publishing apps |
| // of type `app_type`. `publisher` must have a lifetime equal to or longer |
| // than this object. |
| void RegisterPublisher(AppType app_type, AppPublisher* publisher); |
| |
| // UnRegisters the publisher for `app_type`, As the publisher(ArcApps) might |
| // be destroyed earlier than AppServiceProxy. |
| void UnregisterPublisher(AppType app_type); |
| |
| // PreferredAppsImpl::Host overrides. |
| void OnSupportedLinksPreferenceChanged(const std::string& app_id, |
| bool open_in_app) override; |
| |
| // Convenience method that calls app_icon_loader()->LoadIcon to load app icons |
| // with `app_id`. `callback` may be dispatched synchronously if it's possible |
| // to quickly return a result. |
| std::unique_ptr<IconLoader::Releaser> LoadIcon( |
| const std::string& app_id, |
| const IconType& icon_type, |
| int32_t size_hint_in_dip, |
| bool allow_placeholder_icon, |
| apps::LoadIconCallback callback); |
| |
| // Get the default icon effects for the app represented by `app_id`, |
| // which will be used when calling `LoadIcon()` for that app. |
| uint32_t GetIconEffects(const std::string& app_id); |
| |
| // Load the icon for app represented by `app_id`. `icon_effect` can be used to |
| // specify custom icon effect the caller wants to apply on the icon. |
| // `allow_placeholder_icon` indicate whether we allow loading placeholder icon |
| // from the in memory cache and do not attempt to retry to load the actual |
| // icon. |
| std::unique_ptr<IconLoader::Releaser> LoadIconWithIconEffects( |
| const std::string& app_id, |
| uint32_t icon_effects, |
| IconType icon_type, |
| int32_t size_hint_in_dip, |
| bool allow_placeholder_icon, |
| LoadIconCallback callback); |
| |
| // Return the most outer layer of the app icon loader that app service owns. |
| IconLoader* app_icon_loader() { return &app_outer_icon_loader_; } |
| |
| // Launches the app for the given `app_id`. |
| // |
| // - `event_flags` is a bitset of ui::EventFlags providing additional context |
| // about the action which launches the app (e.g. a middle click indicating |
| // opening a background tab). |
| // - `launch_source` is the UI surface which is launching the app (e.g. shelf, |
| // search box). |
| // - `window_info` specifies the desired location of the new app window |
| // (e.g. window bounds, display ID). If `window_info` is nullptr, the app |
| // publisher will position the new app window using its default behavior (e.g. |
| // on the currently active display). |
| // |
| // 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::LaunchSource launch_source, |
| apps::WindowInfoPtr window_info = nullptr); |
| |
| // Launches the app for the given |app_id| with files from |file_paths|. |
| // DEPRECATED. Prefer passing the files in an Intent through |
| // LaunchAppWithIntent. |
| // TODO(crbug.com/40203246): Remove this method. |
| void LaunchAppWithFiles(const std::string& app_id, |
| int32_t event_flags, |
| LaunchSource launch_source, |
| std::vector<base::FilePath> file_paths); |
| |
| // Launches an app for the given `app_id`, passing `intent` to the app. |
| // |
| // - `event_flags` is a bitset of ui::EventFlags providing additional context |
| // about the action which launches the app (e.g. a middle click indicating |
| // opening a background tab). |
| // - `launch_source` is the UI surface which is launching the app (e.g. shelf, |
| // search box). |
| // - `window_info` specifies the desired location of the new app window |
| // (e.g. window bounds, display ID). If `window_info` is nullptr, the app |
| // publisher will position the new app window using its default behavior (e.g. |
| // on the currently active display). |
| // - `callback` will be called with the result of the launch once it is |
| // complete. |
| virtual void LaunchAppWithIntent(const std::string& app_id, |
| int32_t event_flags, |
| IntentPtr intent, |
| LaunchSource launch_source, |
| WindowInfoPtr window_info, |
| LaunchCallback callback); |
| |
| // Launches an app for the given `app_id`, passing `url` to the app. |
| // |
| // - `event_flags` is a bitset of ui::EventFlags providing additional context |
| // about the action which launches the app (e.g. a middle click indicating |
| // opening a background tab). |
| // - `launch_source` is the UI surface which is launching the app (e.g. shelf, |
| // search box). |
| // - `window_info` specifies the desired location of the new app window |
| // (e.g. window bounds, display ID). If `window_info` is nullptr, the app |
| // publisher will position the new app window using its default behavior (e.g. |
| // on the currently active display). |
| // - `callback` will be called with the result of the launch once it is |
| // complete. |
| void LaunchAppWithUrl(const std::string& app_id, |
| int32_t event_flags, |
| GURL url, |
| LaunchSource launch_source, |
| WindowInfoPtr window_info = nullptr, |
| LaunchCallback callback = base::DoNothing()); |
| |
| // Launches an app for the given `params.app_id`. The `params` can also |
| // contain other param such as launch container, window diposition, etc. |
| // Currently the return value in the callback will only be filled up for |
| // Chrome OS web apps and Chrome apps. |
| void LaunchAppWithParams(AppLaunchParams&& params, |
| LaunchCallback callback = base::DoNothing()); |
| |
| // Sets |permission| for the app identified by |app_id|. |
| void SetPermission(const std::string& app_id, PermissionPtr permission); |
| |
| // Uninstalls an app for the given |app_id| without prompting the user to |
| // confirm. |
| void UninstallSilently(const std::string& app_id, |
| 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, |
| MenuType menu_type, |
| int64_t display_id, |
| base::OnceCallback<void(MenuItems)> callback); |
| |
| // Requests the size of an app with |app_id|. Publishers are expected to |
| // calculate and update the size of the app and publish this to App Service. |
| // This allows app sizes to be requested on-demand and ensure up-to-date |
| // values. |
| void UpdateAppSize(const std::string& app_id); |
| |
| // 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); |
| |
| 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<std::string> 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<IntentLaunchInfo> GetAppsForIntent( |
| const apps::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 |files|. |
| std::vector<IntentLaunchInfo> GetAppsForFiles( |
| std::vector<apps::IntentFilePtr> files); |
| |
| // Sets |app_id| as the preferred app for all of its supported links ('view' |
| // intent filters with a scheme and host). Any existing preferred apps for |
| // those links will have all their supported links unset, as if |
| // RemoveSupportedLinksPreference was called for that app. |
| void SetSupportedLinksPreference(const std::string& app_id); |
| |
| // Set |app_id| as preferred app for all its supported link filters. Supported |
| // link filters, which have the http/https scheme and at least one host, are |
| // always enabled/disabled as a group. |all_link_filters| should contain all |
| // of the apps' Supported Link intent filters. |
| // Any apps with overlapping preferred app preferences will have all their |
| // supported link filters unset, as if RemoveSupportedLinksPreference was |
| // called for that app. |
| // TODO(crbug.com/40203720): Remove this method to use |
| // SetSupportedLinksPreference(std::string). |
| void SetSupportedLinksPreference(const std::string& app_id, |
| IntentFilters all_link_filters); |
| |
| // Removes all supported link filters from the preferred app list for |
| // |app_id|. |
| void RemoveSupportedLinksPreference(const std::string& app_id); |
| |
| // Sets the window display mode for the app identified by `app_id`. |
| // `window_mode` represents how the app will be open in (e.g. in a |
| // standalone window or in a browser tab). |
| void SetWindowMode(const std::string& app_id, WindowMode window_mode); |
| |
| // Called by an app publisher to inform the proxy of a change in app state. |
| virtual void OnApps(std::vector<AppPtr> deltas, |
| AppType app_type, |
| bool should_notify_initialized); |
| |
| // Called by an app publisher to inform the proxy of a change in |
| // CapabilityAccess. |
| void OnCapabilityAccesses(std::vector<CapabilityAccessPtr> deltas); |
| |
| protected: |
| // An adapter, presenting an IconLoader interface based on the underlying |
| // service (or on a fake implementation for testing). |
| // |
| // UI clients call through ASP interface to call into the IconLoader owned |
| // by ASP, which will eventually call into this adapter. This adapter then |
| // calls into IconReader to read the icon from App Service Icon storage on |
| // disk. The publishers will install the icon to the App Service Icon storage |
| // if it is not present. This diagram shows control flow going left to right, |
| // and the responses (callbacks) then run right to left in LIFO order: |
| // |
| // UI => ASP => IconLoader => IconReader |
| // | or |
| // +=> 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 => | Outer => MoreDecorators... => Inner | => IconReader |
| // | | | or |
| // +---------------------------------------+ +=> Fake |
| // |
| // The app_inner_icon_loader_ field (of type AppInnerIconLoader) is the |
| // "Inner" component: the one that ultimately talks to the Mojo service. |
| // |
| // The app_outer_icon_loader_ field (of type IconCache) is the "Outer" |
| // component: the entry point for calls into the AppServiceProxyBase. |
| // |
| // 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 AppInnerIconLoader : public apps::IconLoader { |
| public: |
| explicit AppInnerIconLoader(AppServiceProxyBase* host); |
| |
| // apps::IconLoader overrides. |
| std::optional<IconKey> GetIconKey(const std::string& id) override; |
| std::unique_ptr<Releaser> LoadIconFromIconKey( |
| const std::string& id, |
| const IconKey& icon_key, |
| IconType icon_type, |
| int32_t size_hint_in_dip, |
| bool allow_placeholder_icon, |
| apps::LoadIconCallback callback) override; |
| |
| // |host_| owns |this|, as the InnerIconLoader is an AppServiceProxyBase |
| // field. |
| raw_ptr<AppServiceProxyBase> host_; |
| |
| raw_ptr<apps::IconLoader, DanglingUntriaged> |
| overriding_icon_loader_for_testing_; |
| }; |
| |
| virtual bool IsValidProfile(); |
| |
| // Called in AppServiceProxyFactory::BuildServiceInstanceFor immediately |
| // following the creation of AppServiceProxy. Use this method to perform any |
| // operation that depends on a fully instantiated AppServiceProxy (i.e. to |
| // avoid calling other virtual methods in the AppServiceProxy constructor). |
| virtual void Initialize(); |
| |
| AppPublisher* GetPublisher(AppType app_type); |
| |
| // 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). |
| virtual bool MaybeShowLaunchPreventionDialog( |
| const apps::AppUpdate& update) = 0; |
| |
| IntentFilterPtr FindBestMatchingFilter(const IntentPtr& intent); |
| |
| virtual void PerformPostLaunchTasks(apps::LaunchSource launch_source); |
| |
| virtual void RecordAppPlatformMetrics(Profile* profile, |
| const apps::AppUpdate& update, |
| apps::LaunchSource launch_source, |
| apps::LaunchContainer container); |
| |
| virtual void PerformPostUninstallTasks(apps::AppType app_type, |
| const std::string& app_id, |
| UninstallSource uninstall_source); |
| |
| virtual void OnLaunched(LaunchCallback callback, |
| LaunchResult&& launch_result); |
| |
| virtual bool ShouldExcludeBrowserTabApps(bool exclude_browser_tab_apps, |
| WindowMode window_mode); |
| |
| // Returns true if we should read icon image files from the local app_service |
| // icon directory on disk, e.g. for ChromeOS. Otherwise, returns false. |
| virtual bool ShouldReadIcons(AppType app_type); |
| |
| // Reads icon image files from the local app_service icon directory on disk. |
| virtual void ReadIcons(AppType app_type, |
| const std::string& app_id, |
| int32_t size_in_dip, |
| std::unique_ptr<IconKey> icon_key, |
| IconType icon_type, |
| LoadIconCallback callback) {} |
| |
| // Returns an instance of `IntentLaunchInfo` created based on `intent`, |
| // `filter`, and `update`. |
| virtual IntentLaunchInfo CreateIntentLaunchInfo( |
| const apps::IntentPtr& intent, |
| const apps::IntentFilterPtr& filter, |
| const apps::AppUpdate& update); |
| |
| base::flat_map<AppType, AppPublisher*> publishers_; |
| |
| apps::AppRegistryCache app_registry_cache_; |
| apps::AppCapabilityAccessCache app_capability_access_cache_; |
| |
| // 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. |
| AppInnerIconLoader app_inner_icon_loader_; |
| IconCoalescer app_icon_coalescer_; |
| IconCache app_outer_icon_loader_; |
| |
| std::unique_ptr<apps::PreferredAppsImpl> preferred_apps_impl_; |
| |
| raw_ptr<Profile> profile_; |
| |
| // TODO(crbug.com/40122594): Remove BrowserAppLauncher and merge the |
| // interfaces to AppServiceProxyBase when publishers(ExtensionApps and |
| // WebApps) can run on Chrome. |
| std::unique_ptr<apps::BrowserAppLauncher> browser_app_launcher_; |
| |
| bool is_using_testing_profile_ = false; |
| base::OnceClosure dialog_created_callback_; |
| |
| private: |
| // For access to Initialize. |
| friend class AppServiceProxyFactory; |
| |
| // For test access to OnApps. |
| friend class AppServiceProxyPreferredAppsTest; |
| |
| base::WeakPtrFactory<AppServiceProxyBase> weak_factory_{this}; |
| }; |
| |
| } // namespace apps |
| |
| #endif // CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_BASE_H_ |