blob: 713379f99d3869e35201e3fa2e66a160716026d2 [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.
#include "chrome/browser/glic/glic_fre_controller.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/memory/scoped_refptr.h"
#include "base/version_info/channel.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/glic/glic_enums.h"
#include "chrome/browser/glic/glic_fre_dialog_view.h"
#include "chrome/browser/glic/glic_keyed_service.h"
#include "chrome/browser/glic/glic_keyed_service_factory.h"
#include "chrome/browser/glic/glic_pref_names.h"
#include "chrome/browser/glic/launcher/glic_launcher_configuration.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/tabs/public/tab_dialog_manager.h"
#include "chrome/browser/ui/tabs/public/tab_features.h"
#include "chrome/browser/ui/tabs/public/tab_interface.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/chrome_switches.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/web_contents.h"
namespace glic {
constexpr static int kFreDefaultWidth = 512;
constexpr static int kFreDefaultHeight = 614;
GlicFreController::GlicFreController(Profile* profile,
signin::IdentityManager* identity_manager)
: profile_(profile),
auth_controller_(profile, identity_manager, /*use_for_fre=*/true) {}
GlicFreController::~GlicFreController() = default;
void GlicFreController::Shutdown() {
DismissFre();
}
bool GlicFreController::ShouldShowFreDialog() {
PrefService* prefs = profile_->GetPrefs();
if (!first_time_pref_check_done_) {
first_time_pref_check_done_ = true;
// If `--glic-always-open-fre` is present, unset this pref to ensure the FRE
// is shown for testing convenience. Do this only once so that we can test
// the accept flow.
auto* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(::switches::kGlicAlwaysOpenFre)) {
prefs->SetBoolean(prefs::kGlicCompletedFre, false);
}
}
// If the given profile has not previously completed the FRE, then it should
// be shown.
return !prefs->GetBoolean(prefs::kGlicCompletedFre);
}
bool GlicFreController::CanShowFreDialog(Browser* browser) {
// The FRE can only be shown given a valid browser. If there is no browser,
// then an OS-level entrypoint is being used, which should not be possible
// before the FRE has been accepted.
if (!browser) {
return false;
}
// If there is a browser, the FRE can only be shown if no
// other modal is currently being shown on the same tab.
tabs::TabInterface* tab = browser->GetActiveTabInterface();
return tab && tab->CanShowModalUI();
}
void GlicFreController::ShowFreDialog(Browser* browser) {
auth_controller_.CheckAuthBeforeShow(
base::BindOnce(&GlicFreController::ShowFreDialogAfterAuthCheck,
GetWeakPtr(), browser->AsWeakPtr()));
}
void GlicFreController::ShowFreDialogAfterAuthCheck(
base::WeakPtr<Browser> browser,
AuthController::BeforeShowResult result) {
if (result == AuthController::BeforeShowResult::kShowingReauthSigninPage) {
return;
}
// Abort if the browser was closed, to avoid crashing. Note, the user
// shouldn't have much chance to close the browser between ShowFreDialog() and
// ShowFreDialogAfterAuthCheck().
if (!browser) {
return;
}
// Close any existing FRE dialog before showing.
DismissFre();
fre_view_ = new GlicFreDialogView(
profile_, gfx::Size(kFreDefaultWidth, kFreDefaultHeight));
tabs::TabInterface* tab_interface = browser->GetActiveTabInterface();
// Note that this call to `CreateShowDialogAndBlockTabInteraction` is
// necessarily preceded by a call to `CanShowModalUI`. See
// `GlicFreController::CanShowFreDialog`.
// TODO(crbug.com/393400004): This returned widget should be configured to
// use a synchronous close.
fre_widget_ = tab_interface->GetTabFeatures()
->tab_dialog_manager()
->CreateShowDialogAndBlockTabInteraction(fre_view_);
tab_showing_modal_ = tab_interface;
will_detach_subscription_ = tab_showing_modal_->RegisterWillDetach(
base::BindRepeating(&GlicFreController::OnTabShowingModalWillDetach,
base::Unretained(this)));
}
void GlicFreController::DismissFreIfOpenOnActiveTab(Browser* browser) {
if (!browser) {
return;
}
tabs::TabInterface* tab = browser->GetActiveTabInterface();
// If the FRE is being shown on the current tab, close it.
if (fre_widget_ && tab_showing_modal_ == tab) {
DismissFre();
}
}
void GlicFreController::AcceptFre() {
// Update FRE related preferences.
profile_->GetPrefs()->SetBoolean(prefs::kGlicCompletedFre, true);
// Enable the launcher if it is still disabled by default and the browser
// is default or is on the stable channel.
bool is_enabled_default = false;
const bool is_launcher_enabled =
GlicLauncherConfiguration::IsEnabled(&is_enabled_default);
if (is_enabled_default && !is_launcher_enabled) {
base::MakeRefCounted<shell_integration::DefaultBrowserWorker>()
->StartCheckIsDefault(
base::BindOnce(&GlicFreController::OnCheckIsDefaultBrowserFinished,
chrome::GetChannel()));
}
DismissFre();
// Show a glic window attached to the last active browser of the glic
// profile, which should correspond to the browser used by the FRE.
if (Browser* new_attached_browser =
chrome::FindLastActiveWithProfile(profile_)) {
glic::GlicKeyedServiceFactory::GetGlicKeyedService(profile_)->ToggleUI(
new_attached_browser, /*prevent_close=*/true, InvocationSource::kFre);
}
}
void GlicFreController::DismissFre() {
if (fre_widget_) {
fre_view_ = nullptr;
fre_widget_.reset();
tab_showing_modal_ = nullptr;
will_detach_subscription_ = {};
}
}
content::WebContents* GlicFreController::GetWebContents() {
if (!fre_view_) {
return nullptr;
}
return fre_view_->web_contents();
}
// static
void GlicFreController::OnCheckIsDefaultBrowserFinished(
version_info::Channel channel,
shell_integration::DefaultWebClientState state) {
// Don't do anything because a different channel is the default browser
if (state ==
shell_integration::DefaultWebClientState::OTHER_MODE_IS_DEFAULT) {
return;
}
// Enables the launcher if the current browser is the default or
// is on the stable channel.
if (g_browser_process &&
(state == shell_integration::DefaultWebClientState::IS_DEFAULT ||
channel == version_info::Channel::STABLE)) {
g_browser_process->local_state()->SetBoolean(prefs::kGlicLauncherEnabled,
true);
}
}
void GlicFreController::OnTabShowingModalWillDetach(
tabs::TabInterface* tab,
tabs::TabInterface::DetachReason reason) {
DismissFre();
}
bool GlicFreController::IsShowingDialogForTesting() const {
return !!fre_widget_;
}
} // namespace glic