blob: cf027c67f4999c8358a529f445c9456a045adfd8 [file] [log] [blame]
// Copyright 2025 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_GLIC_FRE_GLIC_FRE_CONTROLLER_H_
#define CHROME_BROWSER_GLIC_FRE_GLIC_FRE_CONTROLLER_H_
#include <memory>
#include "base/gtest_prod_util.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "chrome/browser/glic/fre/glic_fre.mojom.h"
#include "chrome/browser/glic/host/auth_controller.h"
#include "chrome/browser/glic/host/glic.mojom.h"
#include "chrome/browser/shell_integration.h"
#include "components/tabs/public/tab_interface.h"
#include "ui/views/widget/widget.h"
class Browser;
class Profile;
namespace content {
class WebContents;
}
namespace version_info {
enum class Channel;
}
namespace views {
class Widget;
}
namespace glic {
class GlicFreDialogView;
// This enum is used to record the reason for the FRE error state.
// These values are persisted to logs.
// LINT.IfChange(FreErrorStateReason)
enum class FreErrorStateReason {
// Sign-in is required.
kSignInRequired = 0,
// Error while re-syncing cookies before showing FRE.
kErrorResyncingCookies = 1,
// Timeout exceeded during loading error.
kTimeoutExceeded = 2,
kMaxValue = kTimeoutExceeded,
};
// LINT.ThenChange(tools/metrics/histograms/metadata/glic/enums.xml:FreErrorStateReason)
// This enum is used for the Glic.Fre.WidgetClosedReason2 histogram.
// It mirrors views::Widget::ClosedReason and adds Glic-specific reasons.
// Entries should not be renumbered and numeric values should never be reused.
// LINT.IfChange(GlicFreWidgetClosedReason)
enum class GlicFreWidgetClosedReason {
kUnspecified = 0,
kEscKeyPressed = 1,
kCloseButtonClicked = 2,
kLostFocus = 3,
kCancelButtonClicked = 4,
kAcceptButtonClicked = 5,
kHostTabClosed = 6,
kHostTabMoved = 7,
kMaxValue = kHostTabMoved,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:GlicFreWidgetClosedReason)
// This class owns and manages the glic FRE modal dialog, and is owned by a
// GlicWindowController.
class GlicFreController {
public:
GlicFreController(const GlicFreController&) = delete;
GlicFreController& operator=(const GlicFreController&) = delete;
GlicFreController(Profile* profile,
signin::IdentityManager* identity_manager);
~GlicFreController();
mojom::FreWebUiState GetWebUiState() const { return webui_state_; }
void WebUiStateChanged(mojom::FreWebUiState new_state);
using WebUiStateChangedCallback =
base::RepeatingCallback<void(mojom::FreWebUiState new_state)>;
// Registers |callback| to be called whenever the WebUi state changes.
base::CallbackListSubscription AddWebUiStateChangedCallback(
WebUiStateChangedCallback callback);
// Close any windows and destroy web contents.
void Shutdown();
// Returns whether the FRE dialog should be shown.
bool ShouldShowFreDialog();
// Returns whether the FRE dialog can be shown. This function also checks
// `TabInterface::CanShowModalUI`, which is a mandatory precondition to
// showing the dialog.
bool CanShowFreDialog(Browser* browser);
// Open the new tab page in the browser and show the FRE in that tab if
// possible.
void OpenFreDialogInNewTab(BrowserWindowInterface* bwi,
mojom::InvocationSource source);
// Shows the FRE dialog. This should only be called if `ShouldShowFreDialog`
// and `CanShowFreDialog` are both satisfied.
void ShowFreDialog(Browser* browser, mojom::InvocationSource source);
// Closes the FRE dialog if it is open on the active tab of `browser`.
void DismissFreIfOpenOnActiveTab(Browser* browser);
// Closes the FRE dialog and immediately opens a glic window attached to
// the same browser.
void AcceptFre();
// Rejects the FRE dialog.
void RejectFre();
// Closes the FRE dialog.
void DismissFre(mojom::FreWebUiState panel);
// Used when the native window is closed directly.
void CloseWithReason(views::Widget::ClosedReason reason);
// Re-sync cookies to FRE webview.
void PrepareForClient(base::OnceCallback<void(bool)> callback);
// Loading timeout was exceeded.
void ExceededTimeoutError();
// Notify FRE controller that the user clicked on a link.
void OnLinkClicked(const GURL& url);
// Attempts to warm the FRE web contents.
void TryPreload();
// Returns true if the FRE web contents are loaded (either because it has been
// preloaded or because it is visible).
bool IsWarmed() const;
// Returns the WebContents from the dialog view.
content::WebContents* GetWebContents();
// Preconnect to the server that hosts the FRE, so that it loads faster.
// Does nothing if the FRE should not be shown.
void MaybePreconnect();
bool IsShowingDialog() const;
bool IsShowingDialogAndStateInitialized() const;
gfx::Size GetFreInitialSize();
void UpdateFreWidgetSize(const gfx::Size& new_size);
void LogWebUiLoadComplete();
AuthController& GetAuthControllerForTesting() { return auth_controller_; }
Profile* profile() { return profile_; }
base::WeakPtr<GlicFreController> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void SetIsShowingDialogForTesting(bool is_showing) {
is_showing_dialog_for_testing_ = is_showing;
}
private:
FRIEND_TEST_ALL_PREFIXES(GlicFreControllerTest,
UpdateLauncherOnFreCompletion);
void ShowFreDialogAfterAuthCheck(base::WeakPtr<Browser> browser,
mojom::InvocationSource source);
static void OnCheckIsDefaultBrowserFinished(
version_info::Channel channel,
shell_integration::DefaultWebClientState state);
// Called when the tab showing the FRE dialog is detached.
void OnTabShowingModalWillDetach(tabs::TabInterface* tab,
tabs::TabInterface::DetachReason reason);
void CreateView();
void RecordMetricsIfDialogIsShowingAndReady();
raw_ptr<Profile> const profile_;
std::unique_ptr<views::Widget> fre_widget_;
std::unique_ptr<GlicFreDialogView> fre_view_;
// This is owned by the GlicFreDialogView but we retain a pointer to it so
// that we can continue to reference it even after `fre_view_` relinquishes
// ownership to the widget.
raw_ptr<content::WebContents> web_contents_ = nullptr;
AuthController auth_controller_;
// The invocation source browser.
raw_ptr<Browser> source_browser_ = nullptr;
// Tracks the tab that the FRE dialog is shown on.
raw_ptr<tabs::TabInterface> tab_showing_modal_;
base::CallbackListSubscription will_detach_subscription_;
mojom::FreWebUiState webui_state_ = mojom::FreWebUiState::kUninitialized;
// List of callbacks to be notified when webui state has changed.
base::RepeatingCallbackList<void(mojom::FreWebUiState)>
webui_state_callback_list_;
// Tracks elapsed time between the request for the FRE to show to the time it
// is fully loaded and showing.
std::optional<base::ElapsedTimer> presentation_timer_;
// Tracks the total time the FRE is open.
std::optional<base::ElapsedTimer> open_timer_;
// Tracks the total time since the FRE completed loading and has entered the
// Ready state.
std::optional<base::ElapsedTimer> interaction_timer_;
// Tracks elapsed time between the start of the WebUI framework loading and
// the moment it's fully loaded. This ends right before the web client begins loading.
std::optional<base::ElapsedTimer> webui_framework_load_timer_;
// Tracks elapsed time between the start of the web client loading and the
// moment it's fully loaded.
std::optional<base::ElapsedTimer> web_client_load_timer_;
// True if the user has accepted the FRE.
bool accepted_ = false;
std::optional<bool> is_showing_dialog_for_testing_;
base::WeakPtrFactory<GlicFreController> weak_ptr_factory_{this};
};
} // namespace glic
#endif // CHROME_BROWSER_GLIC_FRE_GLIC_FRE_CONTROLLER_H_