blob: b446e84e2b6aba3a52cd4a9fe513563e36f8dfa4 [file] [log] [blame]
// Copyright 2019 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_UI_WEB_APPLICATIONS_WEB_APP_LAUNCH_UTILS_H_
#define CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_LAUNCH_UTILS_H_
#include <stdint.h>
#include <memory>
#include <optional>
#include <string>
#include "base/functional/callback_helpers.h"
#include "base/memory/stack_allocated.h"
#include "base/memory/weak_ptr.h"
#include "base/values.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/web_applications/navigation_capturing_navigation_handle_user_data.h"
#include "chrome/browser/web_applications/web_app_ui_manager.h"
#include "components/services/app_service/public/cpp/app_launch_util.h"
#include "components/webapps/common/web_app_id.h"
#include "content/public/browser/navigation_handle.h"
#include "third_party/blink/public/mojom/manifest/display_mode.mojom-shared.h"
#include "ui/gfx/geometry/rect.h"
class Profile;
class Browser;
class GURL;
enum class WindowOpenDisposition;
struct NavigateParams;
namespace apps {
struct AppLaunchParams;
}
namespace content {
class WebContents;
}
namespace web_app {
// This function moves `contents` from the `source_browser` to the
// `target_browser`. In doing so, it attempts to ensure that any logic that
// needs to occur when transitioning between 'app' and 'browser' windows occurs,
// and the all session restore logic is correctly updated. `contents` is not
// required to be the active web contents in `source_browser`.
//
// Note: This will CHECK-fail if `contents` is not in `source_browser`.
void ReparentWebContentsIntoBrowserImpl(
Browser* source_browser,
content::WebContents* contents,
Browser* target_browser,
bool insert_as_pinned_first_tab = false);
class AppBrowserController;
class WithAppResources;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class LaunchedAppType {
kDiy = 0,
kCrafted = 1,
kMaxValue = kCrafted,
};
// Returns information useful for the browser to show UI affordances if a web
// app handles the navigation.
class AppNavigationResult {
STACK_ALLOCATED();
public:
// No navigation capturing will happen for this navigation.
static AppNavigationResult CapturingDisabled();
// The navigation itself will be cancelled.
static AppNavigationResult CancelNavigation();
static AppNavigationResult NoCapturingOverrideBrowser(Browser* browser);
// TODO(crbug.com/370856876): Possibly remove `disposition`.
static AppNavigationResult AuxiliaryContext(WindowOpenDisposition disposition,
base::Value::Dict debug_data);
// TODO(crbug.com/370856876): Possibly remove `source_browser_app_id` and
// `disposition`.
static AppNavigationResult AuxiliaryContextInAppWindow(
const webapps::AppId& source_browser_app_id,
WindowOpenDisposition disposition,
Browser* app_browser,
base::Value::Dict debug_data);
// Populates redirection info in case future redirects apply to an
// application.
static AppNavigationResult NoInitialActionRedirectionHandlingEligible(
std::optional<webapps::AppId> source_browser_app_id,
WindowOpenDisposition disposition,
base::Value::Dict debug_data);
// Create AppNavigationResult for a navigation triggered by user modified link
// clicks that creates a new app container.
static AppNavigationResult ForcedNewAppContext(
std::optional<webapps::AppId> source_browser_app_id,
const webapps::AppId capturing_app_id,
blink::mojom::DisplayMode new_client_display_mode,
Browser* host_browser,
WindowOpenDisposition disposition,
base::Value::Dict debug_data);
// Create AppNavigationResult for a navigation that is captured by non user
// modified link clicks that launch a new app container (either window or
// tab).
static AppNavigationResult CapturedNewClient(
std::optional<webapps::AppId> source_browser_app_id,
const webapps::AppId capturing_app_id,
blink::mojom::DisplayMode new_client_display_mode,
Browser* host_browser,
WindowOpenDisposition disposition,
base::Value::Dict debug_data);
// Create AppNavigationResult for a navigation that is captured by non user
// modified link clicks that uses an existing app container (either window or
// tab).
static AppNavigationResult CapturedNavigateExisting(
std::optional<webapps::AppId> source_browser_app_id,
const webapps::AppId capturing_app_id,
Browser* app_browser,
int browser_tab,
WindowOpenDisposition disposition,
base::Value::Dict debug_data);
AppNavigationResult(AppNavigationResult&&);
AppNavigationResult& operator=(AppNavigationResult&&);
// If false, then `OnWebAppNavigationAfterWebContentsCreation() exits early`.
bool capturing_feature_enabled() const { return capturing_feature_enabled_; }
// The browser instance to perform navigation in, and the tab inside the
// browser if overridden by the web app system. If std::nullopt, performs the
// default navigation behavior in browser_navigator.cc.
const std::optional<std::tuple<Browser*, int>>& browser_tab_override() const {
return browser_tab_override_;
}
// True if the `MaybeHandleAppNavigation` considered this navigation to
// be capturable, and the resulting navigation should be considered a launch
// for the given app (and do things like enqueue launch params and show IPH).
bool perform_app_handling_tasks_in_web_contents() const {
return perform_app_handling_tasks_in_web_contents_;
}
// Information necessary for handling redirection after a response is received
// as part of a navigation.
const NavigationCapturingRedirectionInfo& redirection_info() const {
return redirection_info_;
}
base::Value::Dict TakeDebugData();
private:
AppNavigationResult(
bool capturing_feature_enabled,
std::optional<std::tuple<Browser*, int>> browser_tab_override,
bool perform_app_handling_tasks_in_web_contents,
const NavigationCapturingRedirectionInfo& redirection_info,
base::Value::Dict debug_value);
bool capturing_feature_enabled_ = false;
std::optional<std::tuple<Browser*, int>> browser_tab_override_;
bool perform_app_handling_tasks_in_web_contents_ = false;
NavigationCapturingRedirectionInfo redirection_info_;
// Debug information persisted to chrome://web-app-internals.
base::Value::Dict debug_value_;
};
std::optional<webapps::AppId> GetWebAppForActiveTab(const Browser* browser);
// Clears navigation history prior to user entering app scope.
void PrunePreScopeNavigationHistory(const GURL& scope,
content::WebContents* contents);
// Invokes ReparentWebContentsIntoAppBrowser() for the active tab for the
// web app that has the tab's URL in its scope. Does nothing if there is no web
// app in scope.
Browser* ReparentWebAppForActiveTab(Browser* browser);
// Reparents `contents` into a standalone web app window for `app_id`.
// - If the web app has a launch_handler set to reuse existing windows and there
// are existing web app windows around this will launch the web app into the
// existing window and close `contents`.
// - If the web app is in experimental tabbed mode and has and existing web app
// window, `contents` will be reparented into the existing window.
// - Otherwise a new browser window is created for `contents` to be reparented
// into.
// Returns the browser instance where the reparenting has happened, nullptr
// otherwise. Runs `completion_callback` with the existing `contents`, if it was
// reparented, or with the new `web_contents` that was created if the behavior
// deemed it necessary (like for focus existing and navigate-existing
// use-cases).
Browser* ReparentWebContentsIntoAppBrowser(
content::WebContents* contents,
const webapps::AppId& app_id,
base::OnceCallback<void(content::WebContents*)> completion_callback =
base::DoNothingAs<void(content::WebContents*)>());
// Marks the web contents as being the pinned home tab of a tabbed web app.
void SetWebContentsIsPinnedHomeTab(content::WebContents* contents);
std::unique_ptr<AppBrowserController> MaybeCreateAppBrowserController(
Browser* browser);
void MaybeAddPinnedHomeTab(Browser* browser, const std::string& app_id);
// Shows the navigation capturing IPH if the situation warrants it (e.g. the
// WebAppProvider is available, guardrail metrics are not suppressing it and
// the IPH is permitted to show).
void MaybeShowNavigationCaptureIph(webapps::AppId app_id,
Profile* profile,
Browser* browser);
// This creates appropriate CreateParams for creating a PWA window or PWA popup
// window.
Browser::CreateParams CreateParamsForApp(const webapps::AppId& app_id,
bool is_popup,
bool trusted_source,
const gfx::Rect& window_bounds,
Profile* profile,
bool user_gesture);
Browser* CreateWebAppWindowMaybeWithHomeTab(
const webapps::AppId& app_id,
const Browser::CreateParams& params);
content::WebContents* NavigateWebAppUsingParams(const std::string& app_id,
NavigateParams& nav_params);
// RecordLaunchMetrics methods report UMA metrics. It shouldn't have other
// side-effects (e.g. updating app launch time).
void RecordLaunchMetrics(const webapps::AppId& app_id,
apps::LaunchContainer container,
apps::LaunchSource launch_source,
const GURL& launch_url,
content::WebContents* web_contents);
// Updates statistics about web app launch. For example, app's last launch time
// (populates recently launched app list) and site engagement stats.
void UpdateLaunchStats(content::WebContents* web_contents,
const webapps::AppId& app_id,
const GURL& launch_url);
// Locks that lock apps all have the WithAppResources mixin, allowing any
// app-locking lock to call this method.
void LaunchWebApp(apps::AppLaunchParams params,
LaunchWebAppWindowSetting launch_setting,
Profile& profile,
WithAppResources& app_resources,
LaunchWebAppDebugValueCallback callback);
// Searches all browsers and tabs to find an applicable browser for the given
// `requested_display_mode` and `app_id`, specifically for use with navigation
// capturing. The tabs in each browser are searched for one that matches the
// given `app_id`. This is the priority order of returned items:
// - If a tab is found for `app_id` in a browser that matches the
// `requested_display_mode`, then that is returned.
// - If the `requested_display_mode` is for a standalone PWA:
// - Fall back to look for the first normal browser with a tab matching
// `app_id`.
// - Otherwise return `std::nullopt`.
// - If the `requested_display_mode` is `kBrowser`:
// - Fall back to returning the first normal browser window, and `-1` for the
// tab.
// - Otherwise return `std::nullopt`.
// - Return `std::nullopt` for all other cases.
std::optional<std::pair<Browser*, int>> GetAppHostForCapturing(
const Profile& profile,
const webapps::AppId& app_id,
blink::mojom::DisplayMode requested_display_mode);
// Returns an AppNavigationResult with pertinent details on how to handle a
// navigation if the web app system can do so. If not, the
// `browser_tab_override` is set to be std::nullopt so that ::Navigate() inside
// the browser_navigator code can pick this up. This function may create a
// browser instance, an app window or a new tab as needed.
AppNavigationResult MaybeHandleAppNavigation(
const NavigateParams& navigate_params);
// Will enqueue the given url in the launch params for this web contents. Does
// not check if the url is within scope of the app.
void EnqueueLaunchParams(content::WebContents* contents,
const webapps::AppId& app_id,
const GURL& url,
bool wait_for_navigation_to_complete);
// Handle navigation-related tasks for the app, like enqueuing launch params,
// showing a navigation capturing IPH bubble and storing information necessary
// for handling redirections in the current `WebContents` or `NavigationHandle`,
// after the appropriate app-scoped `WebContents` has been identified and
// prepared for navigation.
void OnWebAppNavigationAfterWebContentsCreation(
web_app::AppNavigationResult app_navigation_result,
const NavigateParams& params,
base::WeakPtr<content::NavigationHandle> navigation_handle);
} // namespace web_app
#endif // CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_LAUNCH_UTILS_H_