blob: cb00d86b7866f3d3997ba3760ab3ec2ec4ee4587 [file] [log] [blame]
// Copyright 2018 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_WEB_APPLICATIONS_WEB_APP_REGISTRAR_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_REGISTRAR_H_
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/check_op.h"
#include "chrome/browser/profiles/profile_manager_observer.h"
#include "chrome/browser/web_applications/components/web_app_constants.h"
#include "chrome/browser/web_applications/components/web_app_id.h"
#include "chrome/browser/web_applications/components/web_application_info.h"
#include "components/services/app_service/public/cpp/file_handler.h"
#include "components/services/app_service/public/cpp/protocol_handler_info.h"
#include "components/services/app_service/public/cpp/url_handler_info.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace web_app {
class AppRegistrarObserver;
class WebApp;
class OsIntegrationManager;
using Registry = std::map<AppId, std::unique_ptr<WebApp>>;
// A registry model. This is a read-only container, which owns WebApp objects.
class WebAppRegistrar : public ProfileManagerObserver {
public:
explicit WebAppRegistrar(Profile* profile);
WebAppRegistrar(const WebAppRegistrar&) = delete;
WebAppRegistrar& operator=(const WebAppRegistrar&) = delete;
~WebAppRegistrar() override;
bool is_empty() const { return registry_.empty(); }
const WebApp* GetAppById(const AppId& app_id) const;
// TODO(https://crbug.com/1182363): should be removed when id is introduced to
// manifest.
const WebApp* GetAppByStartUrl(const GURL& start_url) const;
std::vector<AppId> GetAppsInSyncInstall();
// Returns true if the app was preinstalled and NOT installed via any other
// mechanism.
bool WasInstalledByDefaultOnly(const AppId& app_id) const;
void Start();
void Shutdown();
// Returns whether the app with |app_id| is currently listed in the registry.
// ie. we have data for web app manifest and icons, and this |app_id| can be
// used in other registrar methods.
bool IsInstalled(const AppId& app_id) const;
// Returns whether the app is currently being uninstalled. This will be true
// after uninstall has begun but before the OS integration hooks for uninstall
// have completed. It will return false after uninstallation has completed.
// Note that the underlying field this checks is not yet persisted to the
// database; see https://crbug.com/1162477
bool IsUninstalling(const AppId& app_id) const;
// Returns whether the app with |app_id| is currently fully locally installed.
// ie. app is not grey in chrome://apps UI surface and may have OS integration
// like shortcuts. |IsLocallyInstalled| apps is a subset of |IsInstalled|
// apps. On Chrome OS all apps are always locally installed.
bool IsLocallyInstalled(const AppId& app_id) const;
// Returns true if the app was installed by user, false if default installed.
bool WasInstalledByUser(const AppId& app_id) const;
// Returns true if the app was installed by the device OEM. Always false on
// on non-Chrome OS.
bool WasInstalledByOem(const AppId& app_id) const;
// Returns the AppIds and URLs of apps externally installed from
// |install_source|.
virtual std::map<AppId, GURL> GetExternallyInstalledApps(
ExternalInstallSource install_source) const;
// Returns the app id for |install_url| if the WebAppRegistrar is aware of an
// externally installed app for it. Note that the |install_url| is the URL
// that the app was installed from, which may not necessarily match the app's
// current start URL.
virtual absl::optional<AppId> LookupExternalAppId(
const GURL& install_url) const;
// Returns whether the WebAppRegistrar has an externally installed app with
// |app_id| from any |install_source|.
virtual bool HasExternalApp(const AppId& app_id) const;
// Returns whether the WebAppRegistrar has an externally installed app with
// |app_id| from |install_source|.
virtual bool HasExternalAppWithInstallSource(
const AppId& app_id,
ExternalInstallSource install_source) const;
// Returns true if the web app with the |app_id| contains |protocol_scheme|
// as one of its approved launch protocols.
bool IsApprovedLaunchProtocol(const AppId& app_id,
std::string protocol_scheme) const;
// Count a number of all apps which are installed by user (non-default).
// Requires app registry to be in a ready state.
int CountUserInstalledApps() const;
// All names are UTF8 encoded.
std::string GetAppShortName(const AppId& app_id) const;
std::string GetAppDescription(const AppId& app_id) const;
absl::optional<SkColor> GetAppThemeColor(const AppId& app_id) const;
absl::optional<SkColor> GetAppBackgroundColor(const AppId& app_id) const;
const GURL& GetAppStartUrl(const AppId& app_id) const;
absl::optional<std::string> GetAppManifestId(const AppId& app_id) const;
const std::string* GetAppLaunchQueryParams(const AppId& app_id) const;
const apps::ShareTarget* GetAppShareTarget(const AppId& app_id) const;
blink::mojom::CaptureLinks GetAppCaptureLinks(const AppId& app_id) const;
const apps::FileHandlers* GetAppFileHandlers(const AppId& app_id) const;
const apps::ProtocolHandlers* GetAppProtocolHandlers(
const AppId& app_id) const;
bool IsAppFileHandlerPermissionBlocked(const web_app::AppId& app_id) const;
// Returns the start_url with launch_query_params appended to the end if any.
GURL GetAppLaunchUrl(const AppId& app_id) const;
// TODO(crbug.com/910016): Replace uses of this with GetAppScope().
absl::optional<GURL> GetAppScopeInternal(const AppId& app_id) const;
DisplayMode GetAppDisplayMode(const AppId& app_id) const;
DisplayMode GetAppUserDisplayMode(const AppId& app_id) const;
std::vector<DisplayMode> GetAppDisplayModeOverride(const AppId& app_id) const;
// Returns the "url_handlers" field from the app manifest.
apps::UrlHandlers GetAppUrlHandlers(const AppId& app_id) const;
GURL GetAppManifestUrl(const AppId& app_id) const;
base::Time GetAppLastBadgingTime(const AppId& app_id) const;
base::Time GetAppLastLaunchTime(const AppId& app_id) const;
base::Time GetAppInstallTime(const AppId& app_id) const;
// Returns the "icons" field from the app manifest, use |AppIconManager| to
// load icon bitmap data.
std::vector<WebApplicationIconInfo> GetAppIconInfos(
const AppId& app_id) const;
// Represents which icon sizes we successfully downloaded from the IconInfos.
SortedSizesPx GetAppDownloadedIconSizesAny(const AppId& app_id) const;
// Returns the "shortcuts" field from the app manifest, use |AppIconManager|
// to load shortcuts menu icons bitmaps data.
std::vector<WebApplicationShortcutsMenuItemInfo> GetAppShortcutsMenuItemInfos(
const AppId& app_id) const;
// Represents which icon sizes we successfully downloaded from the
// ShortcutsMenuItemInfos.
std::vector<IconSizes> GetAppDownloadedShortcutsMenuIconsSizes(
const AppId& app_id) const;
// Returns the Run on OS Login mode.
RunOnOsLoginMode GetAppRunOnOsLoginMode(const AppId& app_id) const;
bool GetWindowControlsOverlayEnabled(const AppId& app_id) const;
std::vector<AppId> GetAppIds() const;
// TODO: Remove AsWebAppRegistrar.
WebAppRegistrar* AsWebAppRegistrar();
const WebAppRegistrar* AsWebAppRegistrar() const;
void SetSubsystems(OsIntegrationManager* os_integration_manager);
// Returns the "scope" field from the app manifest, or infers a scope from the
// "start_url" field if unavailable. Returns an invalid GURL iff the |app_id|
// does not refer to an installed web app.
GURL GetAppScope(const AppId& app_id) const;
// Returns the app id of an app in the registry with the longest scope that is
// a prefix of |url|, if any.
absl::optional<AppId> FindAppWithUrlInScope(const GURL& url) const;
// Returns true if there exists at least one app installed under |scope|.
bool DoesScopeContainAnyApp(const GURL& scope) const;
// Finds all apps that are installed under |scope|.
std::vector<AppId> FindAppsInScope(const GURL& scope) const;
// Returns the app id of an installed app in the registry with the longest
// scope that is a prefix of |url|, if any. If |window_only| is specified,
// only apps that open in app windows will be considered.
absl::optional<AppId> FindInstalledAppWithUrlInScope(
const GURL& url,
bool window_only = false) const;
// Returns whether the app is a shortcut app (as opposed to a PWA).
bool IsShortcutApp(const AppId& app_id) const;
// Returns true if the app with the specified |start_url| is currently fully
// locally installed. The provided |start_url| must exactly match the launch
// URL for the app; this method does not consult the app scope or match URLs
// that fall within the scope.
bool IsLocallyInstalled(const GURL& start_url) const;
// Returns whether the app is pending successful navigation in order to
// complete installation via the ExternallyManagedAppManager.
bool IsPlaceholderApp(const AppId& app_id) const;
// Computes and returns the DisplayMode, accounting for user preference
// to launch in a browser window and entries in the web app manifest.
DisplayMode GetAppEffectiveDisplayMode(const AppId& app_id) const;
// Computes and returns the DisplayMode only accounting for
// entries in the web app manifest.
DisplayMode GetEffectiveDisplayModeFromManifest(const AppId& app_id) const;
// Returns whether the app should be opened in tabbed window mode.
bool IsTabbedWindowModeEnabled(const AppId& app_id) const;
// TODO(crbug.com/897314): This can be removed once feature has launched.
bool IsInExperimentalTabbedWindowMode(const AppId& app_id) const;
void AddObserver(AppRegistrarObserver* observer);
void RemoveObserver(AppRegistrarObserver* observer);
void NotifyWebAppInstalled(const AppId& app_id);
void NotifyWebAppManifestUpdated(const AppId& app_id,
base::StringPiece old_name);
void NotifyWebAppsWillBeUpdatedFromSync(
const std::vector<const WebApp*>& new_apps_state);
void NotifyWebAppUninstalled(const AppId& app_id);
void NotifyWebAppWillBeUninstalled(const AppId& app_id);
void NotifyWebAppLocallyInstalledStateChanged(const AppId& app_id,
bool is_locally_installed);
void NotifyWebAppDisabledStateChanged(const AppId& app_id, bool is_disabled);
void NotifyWebAppsDisabledModeChanged();
void NotifyWebAppLastLaunchTimeChanged(const AppId& app_id,
const base::Time& time);
void NotifyWebAppInstallTimeChanged(const AppId& app_id,
const base::Time& time);
// Notify when OS hooks installation is finished during Web App installation.
void NotifyWebAppInstalledWithOsHooks(const AppId& app_id);
void NotifyWebAppUserDisplayModeChanged(const AppId& app_id,
DisplayMode user_display_mode);
void NotifyWebAppExperimentalTabbedWindowModeChanged(const AppId& app_id,
bool enabled);
// ProfileManagerObserver:
void OnProfileMarkedForPermanentDeletion(
Profile* profile_to_be_deleted) override;
// A filter must return false to skip the |web_app|.
using Filter = bool (*)(const WebApp& web_app);
// Only range-based |for| loop supported. Don't use AppSet directly.
// Doesn't support registration and unregistration of WebApp while iterating.
class AppSet {
public:
// An iterator class that can be used to access the list of apps.
template <typename WebAppType>
class Iter {
public:
using InternalIter = Registry::const_iterator;
Iter(InternalIter&& internal_iter,
InternalIter&& internal_end,
Filter filter)
: internal_iter_(std::move(internal_iter)),
internal_end_(std::move(internal_end)),
filter_(filter) {
FilterAndSkipApps();
}
Iter(Iter&&) = default;
Iter(const Iter&) = delete;
Iter& operator=(const Iter&) = delete;
~Iter() = default;
void operator++() {
++internal_iter_;
FilterAndSkipApps();
}
WebAppType& operator*() const { return *internal_iter_->second.get(); }
bool operator!=(const Iter& iter) const {
return internal_iter_ != iter.internal_iter_;
}
private:
void FilterAndSkipApps() {
if (!filter_)
return;
while (internal_iter_ != internal_end_ && !filter_(**this))
++internal_iter_;
}
InternalIter internal_iter_;
InternalIter internal_end_;
Filter filter_;
};
AppSet(const WebAppRegistrar* registrar, Filter filter);
AppSet(AppSet&&) = default;
AppSet(const AppSet&) = delete;
AppSet& operator=(const AppSet&) = delete;
~AppSet();
using iterator = Iter<WebApp>;
using const_iterator = Iter<const WebApp>;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
private:
const WebAppRegistrar* const registrar_;
const Filter filter_;
#if DCHECK_IS_ON()
const size_t mutations_count_;
#endif
};
// Returns all apps in the registry (a superset) including stubs.
const AppSet GetAppsIncludingStubs() const;
// Returns all apps excluding stubs for apps in sync install. Apps in sync
// install are being installed and should be hidden for most subsystems. This
// is a subset of GetAppsIncludingStubs().
const AppSet GetApps() const;
protected:
Profile* profile() const { return profile_; }
OsIntegrationManager& os_integration_manager() {
return *os_integration_manager_;
}
void NotifyWebAppProfileWillBeDeleted(const AppId& app_id);
void NotifyAppRegistrarShutdown();
Registry& registry() { return registry_; }
void SetRegistry(Registry&& registry);
const AppSet FilterApps(Filter filter) const;
void CountMutation();
private:
Profile* const profile_;
base::ObserverList<AppRegistrarObserver, /*check_empty=*/true> observers_;
OsIntegrationManager* os_integration_manager_ = nullptr;
Registry registry_;
bool registry_profile_being_deleted_ = false;
#if DCHECK_IS_ON()
size_t mutations_count_ = 0;
#endif
};
// A writable API for the registry model. Mutable WebAppRegistrar must be used
// only by WebAppSyncBridge.
class WebAppRegistrarMutable : public WebAppRegistrar {
public:
explicit WebAppRegistrarMutable(Profile* profile);
~WebAppRegistrarMutable() override;
void InitRegistry(Registry&& registry);
WebApp* GetAppByIdMutable(const AppId& app_id);
AppSet FilterAppsMutable(Filter filter);
AppSet GetAppsIncludingStubsMutable();
AppSet GetAppsMutable();
using WebAppRegistrar::CountMutation;
using WebAppRegistrar::registry;
};
// For testing and debug purposes.
bool IsRegistryEqual(const Registry& registry, const Registry& registry2);
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_REGISTRAR_H_