blob: 57d820177d08e6ce8a5f2be0430552bde1a3f34a [file] [log] [blame]
// Copyright 2020 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.
#include "chrome/browser/ui/profile_picker.h"
#include <algorithm>
#include <string>
#include "base/containers/flat_set.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/signin/signin_util.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/webui_url_constants.h"
#include "components/prefs/pref_service.h"
namespace {
constexpr base::TimeDelta kActiveTimeThreshold = base::Days(28);
ProfilePicker::AvailabilityOnStartup GetAvailabilityOnStartup() {
int availability_on_startup = g_browser_process->local_state()->GetInteger(
prefs::kBrowserProfilePickerAvailabilityOnStartup);
switch (availability_on_startup) {
case 0:
return ProfilePicker::AvailabilityOnStartup::kEnabled;
case 1:
return ProfilePicker::AvailabilityOnStartup::kDisabled;
case 2:
return ProfilePicker::AvailabilityOnStartup::kForced;
default:
NOTREACHED();
}
return ProfilePicker::AvailabilityOnStartup::kEnabled;
}
} // namespace
const char ProfilePicker::kTaskManagerUrl[] =
"chrome://profile-picker/task-manager";
ProfilePicker::Params::~Params() {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
NotifyAccountSelected(std::string());
NotifyFirstRunExited(FirstRunExitStatus::kQuitEarly, base::OnceClosure());
#endif
}
ProfilePicker::Params::Params(ProfilePicker::Params&&) = default;
ProfilePicker::Params& ProfilePicker::Params::operator=(
ProfilePicker::Params&&) = default;
// static
ProfilePicker::Params ProfilePicker::Params::FromEntryPoint(
EntryPoint entry_point) {
// Use specialized constructors when available.
DCHECK_NE(entry_point, EntryPoint::kBackgroundModeManager);
DCHECK_NE(entry_point, EntryPoint::kLacrosSelectAvailableAccount);
DCHECK_NE(entry_point, EntryPoint::kLacrosPrimaryProfileFirstRun);
return ProfilePicker::Params(entry_point, GetPickerProfilePath());
}
// static
ProfilePicker::Params ProfilePicker::Params::ForBackgroundManager(
const GURL& on_select_profile_target_url) {
Params params(EntryPoint::kBackgroundModeManager, GetPickerProfilePath());
params.on_select_profile_target_url_ = on_select_profile_target_url;
return params;
}
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// static
ProfilePicker::Params ProfilePicker::Params::ForLacrosSelectAvailableAccount(
const base::FilePath& profile_path,
base::OnceCallback<void(const std::string&)> account_selected_callback) {
Params params(EntryPoint::kLacrosSelectAvailableAccount,
profile_path.empty() ? GetPickerProfilePath() : profile_path);
params.account_selected_callback_ = std::move(account_selected_callback);
return params;
}
// static
ProfilePicker::Params ProfilePicker::Params::ForLacrosPrimaryProfileFirstRun(
FirstRunExitedCallback first_run_finished_callback) {
Params params(EntryPoint::kLacrosPrimaryProfileFirstRun,
ProfileManager::GetPrimaryUserProfilePath());
params.first_run_exited_callback_ = std::move(first_run_finished_callback);
return params;
}
void ProfilePicker::Params::NotifyAccountSelected(const std::string& gaia_id) {
if (account_selected_callback_)
std::move(account_selected_callback_).Run(gaia_id);
}
void ProfilePicker::Params::NotifyFirstRunExited(
FirstRunExitStatus exit_status,
base::OnceClosure maybe_callback) {
if (first_run_exited_callback_)
std::move(first_run_exited_callback_)
.Run(exit_status, std::move(maybe_callback));
}
#endif
GURL ProfilePicker::Params::GetInitialURL() const {
GURL base_url = GURL(chrome::kChromeUIProfilePickerUrl);
switch (entry_point_) {
case ProfilePicker::EntryPoint::kOnStartup: {
GURL::Replacements replacements;
replacements.SetQueryStr(chrome::kChromeUIProfilePickerStartupQuery);
return base_url.ReplaceComponents(replacements);
}
case ProfilePicker::EntryPoint::kProfileMenuManageProfiles:
case ProfilePicker::EntryPoint::kOpenNewWindowAfterProfileDeletion:
case ProfilePicker::EntryPoint::kNewSessionOnExistingProcess:
case ProfilePicker::EntryPoint::kProfileLocked:
case ProfilePicker::EntryPoint::kUnableToCreateBrowser:
case ProfilePicker::EntryPoint::kBackgroundModeManager:
return base_url;
case ProfilePicker::EntryPoint::kProfileMenuAddNewProfile:
return base_url.Resolve("new-profile");
case ProfilePicker::EntryPoint::kLacrosSelectAvailableAccount:
return base_url.Resolve("account-selection-lacros");
case ProfilePicker::EntryPoint::kLacrosPrimaryProfileFirstRun:
// No web UI should be displayed initially.
NOTREACHED();
return GURL();
}
}
bool ProfilePicker::Params::CanReusePickerWindow(const Params& other) const {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// Some entry points have specific UIs that cannot be reused for other entry
// points.
base::flat_set<EntryPoint> exclusive_entry_points = {
EntryPoint::kLacrosPrimaryProfileFirstRun,
EntryPoint::kLacrosSelectAvailableAccount};
if (entry_point_ != other.entry_point_ &&
(exclusive_entry_points.contains(entry_point_) ||
exclusive_entry_points.contains(other.entry_point_))) {
return false;
}
return profile_path_ == other.profile_path_;
#else
DCHECK_EQ(profile_path_, other.profile_path_);
return true;
#endif
}
ProfilePicker::Params::Params(EntryPoint entry_point,
const base::FilePath& profile_path)
: entry_point_(entry_point), profile_path_(profile_path) {}
// static
bool ProfilePicker::Shown() {
PrefService* prefs = g_browser_process->local_state();
DCHECK(prefs);
return prefs->GetBoolean(prefs::kBrowserProfilePickerShown);
}
// static
bool ProfilePicker::ShouldShowAtLaunch() {
AvailabilityOnStartup availability_on_startup = GetAvailabilityOnStartup();
if (availability_on_startup == AvailabilityOnStartup::kDisabled)
return false;
// TODO (crbug/1155158): Move this over the urls check (in
// startup_browser_creator.cc) once the profile picker can forward urls
// specified in command line.
if (availability_on_startup == AvailabilityOnStartup::kForced)
return true;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// Don't show the profile picker if secondary profiles are not allowed.
bool lacros_secondary_profiles_allowed =
g_browser_process->local_state()->GetBoolean(
prefs::kLacrosSecondaryProfilesAllowed);
if (!lacros_secondary_profiles_allowed)
return false;
#endif
ProfileManager* profile_manager = g_browser_process->profile_manager();
size_t number_of_profiles = profile_manager->GetNumberOfProfiles();
// Need to consider 0 profiles as this is what happens in some browser-tests.
if (number_of_profiles <= 1)
return false;
std::vector<ProfileAttributesEntry*> profile_attributes =
profile_manager->GetProfileAttributesStorage().GetAllProfilesAttributes();
int number_of_active_profiles =
std::count_if(profile_attributes.begin(), profile_attributes.end(),
[](ProfileAttributesEntry* entry) {
return (base::Time::Now() - entry->GetActiveTime() <
kActiveTimeThreshold);
});
// Don't show the profile picker at launch if the user has less than two
// active profiles. However, if the user has already seen the profile picker
// before, respect user's preference.
if (number_of_active_profiles < 2 && !Shown())
return false;
bool pref_enabled = g_browser_process->local_state()->GetBoolean(
prefs::kBrowserShowProfilePickerOnStartup);
base::UmaHistogramBoolean("ProfilePicker.AskOnStartup", pref_enabled);
return pref_enabled;
}