1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/profiles/profile_window.h"
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/about_flags.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/lifetime/application_lifetime.h"
15 #include "chrome/browser/pref_service_flags_storage.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/browser/signin/account_reconcilor_factory.h"
20 #include "chrome/browser/signin/account_tracker_service_factory.h"
21 #include "chrome/browser/signin/signin_manager_factory.h"
22 #include "chrome/browser/signin/signin_ui_util.h"
23 #include "chrome/browser/sync/profile_sync_service.h"
24 #include "chrome/browser/sync/profile_sync_service_factory.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_dialogs.h"
27 #include "chrome/browser/ui/profile_chooser_constants.h"
28 #include "chrome/browser/ui/user_manager.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/common/url_constants.h"
32 #include "components/signin/core/browser/account_reconcilor.h"
33 #include "components/signin/core/browser/account_tracker_service.h"
34 #include "components/signin/core/browser/signin_manager.h"
35 #include "components/signin/core/common/profile_management_switches.h"
36 #include "content/public/browser/browser_thread.h"
37 #include "content/public/browser/user_metrics.h"
39 #if defined(ENABLE_EXTENSIONS)
40 #include "chrome/browser/extensions/extension_service.h"
41 #include "extensions/browser/extension_prefs.h"
42 #include "extensions/browser/extension_registry.h"
43 #include "extensions/browser/extension_registry_factory.h"
44 #include "extensions/browser/extension_system.h"
45 #endif // defined(ENABLE_EXTENSIONS)
48 #include "chrome/browser/ui/browser_finder.h"
49 #include "chrome/browser/ui/browser_list.h"
50 #include "chrome/browser/ui/browser_list_observer.h"
51 #include "chrome/browser/ui/browser_window.h"
52 #include "chrome/browser/ui/startup/startup_browser_creator.h"
53 #endif // !defined (OS_IOS)
55 using base::UserMetricsAction
;
56 using content::BrowserThread
;
60 const char kNewProfileManagementExperimentInternalName
[] =
61 "enable-new-profile-management";
63 #if defined(ENABLE_EXTENSIONS)
64 void BlockExtensions(Profile
* profile
) {
65 ExtensionService
* extension_service
=
66 extensions::ExtensionSystem::Get(profile
)->extension_service();
67 extension_service
->BlockAllExtensions();
70 void UnblockExtensions(Profile
* profile
) {
71 ExtensionService
* extension_service
=
72 extensions::ExtensionSystem::Get(profile
)->extension_service();
73 extension_service
->UnblockAllExtensions();
75 #endif // defined(ENABLE_EXTENSIONS)
77 // Handles running a callback when a new Browser for the given profile
78 // has been completely created.
79 class BrowserAddedForProfileObserver
: public chrome::BrowserListObserver
{
81 BrowserAddedForProfileObserver(
83 ProfileManager::CreateCallback callback
)
86 DCHECK(!callback_
.is_null());
87 BrowserList::AddObserver(this);
89 ~BrowserAddedForProfileObserver() override
{}
92 // Overridden from BrowserListObserver:
93 void OnBrowserAdded(Browser
* browser
) override
{
94 if (browser
->profile() == profile_
) {
95 BrowserList::RemoveObserver(this);
96 callback_
.Run(profile_
, Profile::CREATE_STATUS_INITIALIZED
);
97 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
101 // Profile for which the browser should be opened.
103 ProfileManager::CreateCallback callback_
;
105 DISALLOW_COPY_AND_ASSIGN(BrowserAddedForProfileObserver
);
108 void OpenBrowserWindowForProfile(
109 ProfileManager::CreateCallback callback
,
112 chrome::HostDesktopType desktop_type
,
114 Profile::CreateStatus status
) {
115 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
117 if (status
!= Profile::CREATE_STATUS_INITIALIZED
)
120 chrome::startup::IsProcessStartup is_process_startup
=
121 chrome::startup::IS_NOT_PROCESS_STARTUP
;
122 chrome::startup::IsFirstRun is_first_run
= chrome::startup::IS_NOT_FIRST_RUN
;
124 // If this is a brand new profile, then start a first run window.
125 if (is_new_profile
) {
126 is_process_startup
= chrome::startup::IS_PROCESS_STARTUP
;
127 is_first_run
= chrome::startup::IS_FIRST_RUN
;
130 #if defined(ENABLE_EXTENSIONS)
131 // The signin bit will still be set if the profile is being unlocked and the
132 // browser window for it is opening. As part of this unlock process, unblock
133 // all the extensions.
134 const ProfileInfoCache
& cache
=
135 g_browser_process
->profile_manager()->GetProfileInfoCache();
136 int index
= cache
.GetIndexOfProfileWithPath(profile
->GetPath());
137 if (!profile
->IsGuestSession() &&
138 cache
.ProfileIsSigninRequiredAtIndex(index
)) {
139 UnblockExtensions(profile
);
141 #endif // defined(ENABLE_EXTENSIONS)
143 // If |always_create| is false, and we have a |callback| to run, check
144 // whether a browser already exists so that we can run the callback. We don't
145 // want to rely on the observer listening to OnBrowserSetLastActive in this
146 // case, as you could manually activate an incorrect browser and trigger
148 if (!always_create
) {
149 Browser
* browser
= chrome::FindTabbedBrowser(profile
, false, desktop_type
);
151 browser
->window()->Activate();
152 if (!callback
.is_null())
153 callback
.Run(profile
, Profile::CREATE_STATUS_INITIALIZED
);
158 // If there is a callback, create an observer to make sure it is only
159 // run when the browser has been completely created. This observer will
160 // delete itself once that happens. This should not leak, because we are
161 // passing |always_create| = true to FindOrCreateNewWindow below, which ends
162 // up calling LaunchBrowser and opens a new window. If for whatever reason
163 // that fails, either something has crashed, or the observer will be cleaned
164 // up when a different browser for this profile is opened.
165 if (!callback
.is_null())
166 new BrowserAddedForProfileObserver(profile
, callback
);
168 // We already dealt with the case when |always_create| was false and a browser
169 // existed, which means that here a browser definitely needs to be created.
170 // Passing true for |always_create| means we won't duplicate the code that
171 // tries to find a browser.
172 profiles::FindOrCreateNewWindowForProfile(
180 // Called after a |system_profile| is available to be used by the user manager.
181 // Based on the value of |tutorial_mode| we determine a url to be displayed
182 // by the webui and run the |callback|, if it exists. After opening a profile,
183 // perform |profile_open_action|.
184 void OnUserManagerSystemProfileCreated(
185 const base::FilePath
& profile_path_to_focus
,
186 profiles::UserManagerTutorialMode tutorial_mode
,
187 profiles::UserManagerProfileSelected profile_open_action
,
188 const base::Callback
<void(Profile
*, const std::string
&)>& callback
,
189 Profile
* system_profile
,
190 Profile::CreateStatus status
) {
191 if (status
!= Profile::CREATE_STATUS_INITIALIZED
|| callback
.is_null())
194 // Tell the webui which user should be focused.
195 std::string page
= chrome::kChromeUIUserManagerURL
;
197 if (tutorial_mode
== profiles::USER_MANAGER_TUTORIAL_OVERVIEW
) {
198 page
+= profiles::kUserManagerDisplayTutorial
;
199 } else if (!profile_path_to_focus
.empty()) {
200 const ProfileInfoCache
& cache
=
201 g_browser_process
->profile_manager()->GetProfileInfoCache();
202 size_t index
= cache
.GetIndexOfProfileWithPath(profile_path_to_focus
);
203 if (index
!= std::string::npos
) {
205 page
+= base::IntToString(index
);
207 } else if (profile_open_action
==
208 profiles::USER_MANAGER_SELECT_PROFILE_TASK_MANAGER
) {
209 page
+= profiles::kUserManagerSelectProfileTaskManager
;
210 } else if (profile_open_action
==
211 profiles::USER_MANAGER_SELECT_PROFILE_ABOUT_CHROME
) {
212 page
+= profiles::kUserManagerSelectProfileAboutChrome
;
213 } else if (profile_open_action
==
214 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_SETTINGS
) {
215 page
+= profiles::kUserManagerSelectProfileChromeSettings
;
216 } else if (profile_open_action
==
217 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_MEMORY
) {
218 page
+= profiles::kUserManagerSelectProfileChromeMemory
;
219 } else if (profile_open_action
==
220 profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER
) {
221 page
+= profiles::kUserManagerSelectProfileAppLauncher
;
223 callback
.Run(system_profile
, page
);
226 // Updates Chrome services that require notification when
227 // the new_profile_management's status changes.
228 void UpdateServicesWithNewProfileManagementFlag(Profile
* profile
,
229 bool new_flag_status
) {
230 AccountReconcilor
* account_reconcilor
=
231 AccountReconcilorFactory::GetForProfile(profile
);
232 account_reconcilor
->OnNewProfileManagementFlagChanged(new_flag_status
);
239 // User Manager parameters are prefixed with hash.
240 const char kUserManagerDisplayTutorial
[] = "#tutorial";
241 const char kUserManagerSelectProfileTaskManager
[] = "#task-manager";
242 const char kUserManagerSelectProfileAboutChrome
[] = "#about-chrome";
243 const char kUserManagerSelectProfileChromeSettings
[] = "#chrome-settings";
244 const char kUserManagerSelectProfileChromeMemory
[] = "#chrome-memory";
245 const char kUserManagerSelectProfileAppLauncher
[] = "#app-launcher";
247 void FindOrCreateNewWindowForProfile(
249 chrome::startup::IsProcessStartup process_startup
,
250 chrome::startup::IsFirstRun is_first_run
,
251 chrome::HostDesktopType desktop_type
,
252 bool always_create
) {
258 if (!always_create
) {
259 Browser
* browser
= chrome::FindTabbedBrowser(profile
, false, desktop_type
);
261 browser
->window()->Activate();
266 content::RecordAction(UserMetricsAction("NewWindow"));
267 base::CommandLine
command_line(base::CommandLine::NO_PROGRAM
);
268 StartupBrowserCreator browser_creator
;
269 browser_creator
.LaunchBrowser(
270 command_line
, profile
, base::FilePath(), process_startup
, is_first_run
);
271 #endif // defined(OS_IOS)
274 void SwitchToProfile(const base::FilePath
& path
,
275 chrome::HostDesktopType desktop_type
,
277 ProfileManager::CreateCallback callback
,
278 ProfileMetrics::ProfileOpen metric
) {
279 ProfileMetrics::LogProfileSwitch(metric
,
280 g_browser_process
->profile_manager(),
282 g_browser_process
->profile_manager()->CreateProfileAsync(
284 base::Bind(&OpenBrowserWindowForProfile
,
294 void SwitchToGuestProfile(chrome::HostDesktopType desktop_type
,
295 ProfileManager::CreateCallback callback
) {
296 const base::FilePath
& path
= ProfileManager::GetGuestProfilePath();
297 ProfileMetrics::LogProfileSwitch(ProfileMetrics::SWITCH_PROFILE_GUEST
,
298 g_browser_process
->profile_manager(),
300 g_browser_process
->profile_manager()->CreateProfileAsync(
302 base::Bind(&OpenBrowserWindowForProfile
,
312 bool HasProfileSwitchTargets(Profile
* profile
) {
313 size_t min_profiles
= profile
->IsGuestSession() ? 1 : 2;
314 size_t number_of_profiles
=
315 g_browser_process
->profile_manager()->GetNumberOfProfiles();
316 return number_of_profiles
>= min_profiles
;
319 void CreateAndSwitchToNewProfile(chrome::HostDesktopType desktop_type
,
320 ProfileManager::CreateCallback callback
,
321 ProfileMetrics::ProfileAdd metric
) {
322 ProfileInfoCache
& cache
=
323 g_browser_process
->profile_manager()->GetProfileInfoCache();
325 int placeholder_avatar_index
= profiles::GetPlaceholderAvatarIndex();
326 ProfileManager::CreateMultiProfileAsync(
327 cache
.ChooseNameForNewProfile(placeholder_avatar_index
),
328 base::UTF8ToUTF16(profiles::GetDefaultAvatarIconUrl(
329 placeholder_avatar_index
)),
330 base::Bind(&OpenBrowserWindowForProfile
,
336 ProfileMetrics::LogProfileAddNewUser(metric
);
339 void GuestBrowserCloseSuccess(const base::FilePath
& profile_path
) {
340 UserManager::Show(base::FilePath(),
341 profiles::USER_MANAGER_NO_TUTORIAL
,
342 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
345 void CloseGuestProfileWindows() {
346 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
347 Profile
* profile
= profile_manager
->GetProfileByPath(
348 ProfileManager::GetGuestProfilePath());
351 BrowserList::CloseAllBrowsersWithProfile(
352 profile
, base::Bind(&GuestBrowserCloseSuccess
));
356 void LockBrowserCloseSuccess(const base::FilePath
& profile_path
) {
357 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
358 ProfileInfoCache
* cache
= &profile_manager
->GetProfileInfoCache();
360 cache
->SetProfileSigninRequiredAtIndex(
361 cache
->GetIndexOfProfileWithPath(profile_path
), true);
363 #if defined(ENABLE_EXTENSIONS)
364 // Profile guaranteed to exist for it to have been locked.
365 BlockExtensions(profile_manager
->GetProfileByPath(profile_path
));
366 #endif // defined(ENABLE_EXTENSIONS)
368 chrome::HideTaskManager();
369 UserManager::Show(profile_path
,
370 profiles::USER_MANAGER_NO_TUTORIAL
,
371 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
374 void LockProfile(Profile
* profile
) {
377 BrowserList::CloseAllBrowsersWithProfile(
378 profile
, base::Bind(&LockBrowserCloseSuccess
));
382 bool IsLockAvailable(Profile
* profile
) {
384 if (!switches::IsNewProfileManagement())
387 if (profile
->IsGuestSession() || profile
->IsSystemProfile())
390 std::string hosted_domain
= profile
->GetPrefs()->
391 GetString(prefs::kGoogleServicesHostedDomain
);
392 // TODO(mlerman): After one release remove any hosted_domain reference to the
393 // pref, since all users will have this in the AccountTrackerService.
394 if (hosted_domain
.empty()) {
395 AccountTrackerService
* account_tracker
=
396 AccountTrackerServiceFactory::GetForProfile(profile
);
397 std::string account_id
=
398 SigninManagerFactory::GetForProfile(profile
)->GetAuthenticatedAccountId();
399 hosted_domain
= account_tracker
->GetAccountInfo(account_id
).hosted_domain
;
401 // TODO(mlerman): Prohibit only users who authenticate using SAML. Until then,
402 // prohibited users who use hosted domains (aside from google.com).
403 if (hosted_domain
!= Profile::kNoHostedDomainFound
&&
404 hosted_domain
!= "google.com") {
408 const ProfileInfoCache
& cache
=
409 g_browser_process
->profile_manager()->GetProfileInfoCache();
410 for (size_t i
= 0; i
< cache
.GetNumberOfProfiles(); ++i
) {
411 if (cache
.ProfileIsSupervisedAtIndex(i
))
417 void CreateSystemProfileForUserManager(
418 const base::FilePath
& profile_path_to_focus
,
419 profiles::UserManagerTutorialMode tutorial_mode
,
420 profiles::UserManagerProfileSelected profile_open_action
,
421 const base::Callback
<void(Profile
*, const std::string
&)>& callback
) {
422 // Create the system profile, if necessary, and open the User Manager
423 // from the system profile.
424 g_browser_process
->profile_manager()->CreateProfileAsync(
425 ProfileManager::GetSystemProfilePath(),
426 base::Bind(&OnUserManagerSystemProfileCreated
,
427 profile_path_to_focus
,
436 void ShowUserManagerMaybeWithTutorial(Profile
* profile
) {
437 // Guest users cannot appear in the User Manager, nor display a tutorial.
438 if (!profile
|| profile
->IsGuestSession()) {
439 UserManager::Show(base::FilePath(),
440 profiles::USER_MANAGER_NO_TUTORIAL
,
441 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
444 UserManager::Show(base::FilePath(),
445 profiles::USER_MANAGER_TUTORIAL_OVERVIEW
,
446 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
449 void EnableNewProfileManagementPreview(Profile
* profile
) {
450 #if defined(OS_ANDROID)
453 // TODO(rogerta): instead of setting experiment flags and command line
454 // args, we should set a profile preference.
455 const about_flags::Experiment experiment
= {
456 kNewProfileManagementExperimentInternalName
,
457 0, // string id for title of experiment
458 0, // string id for description of experiment
459 0, // supported platforms
460 about_flags::Experiment::ENABLE_DISABLE_VALUE
,
461 switches::kEnableNewProfileManagement
,
462 "", // not used with ENABLE_DISABLE_VALUE type
463 switches::kDisableNewProfileManagement
,
464 "", // not used with ENABLE_DISABLE_VALUE type
465 NULL
, // not used with ENABLE_DISABLE_VALUE type
468 about_flags::PrefServiceFlagsStorage
flags_storage(
469 g_browser_process
->local_state());
470 about_flags::SetExperimentEnabled(
472 experiment
.NameForChoice(1),
475 switches::EnableNewProfileManagementForTesting(
476 base::CommandLine::ForCurrentProcess());
477 UserManager::Show(base::FilePath(),
478 profiles::USER_MANAGER_TUTORIAL_OVERVIEW
,
479 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
480 UpdateServicesWithNewProfileManagementFlag(profile
, true);
484 void DisableNewProfileManagementPreview(Profile
* profile
) {
485 about_flags::PrefServiceFlagsStorage
flags_storage(
486 g_browser_process
->local_state());
487 about_flags::SetExperimentEnabled(
489 kNewProfileManagementExperimentInternalName
,
491 chrome::AttemptRestart();
492 UpdateServicesWithNewProfileManagementFlag(profile
, false);
495 void BubbleViewModeFromAvatarBubbleMode(
496 BrowserWindow::AvatarBubbleMode mode
,
497 BubbleViewMode
* bubble_view_mode
,
498 TutorialMode
* tutorial_mode
) {
499 *tutorial_mode
= TUTORIAL_MODE_NONE
;
501 case BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT
:
502 *bubble_view_mode
= BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
;
504 case BrowserWindow::AVATAR_BUBBLE_MODE_SIGNIN
:
505 *bubble_view_mode
= BUBBLE_VIEW_MODE_GAIA_SIGNIN
;
507 case BrowserWindow::AVATAR_BUBBLE_MODE_ADD_ACCOUNT
:
508 *bubble_view_mode
= BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
;
510 case BrowserWindow::AVATAR_BUBBLE_MODE_REAUTH
:
511 *bubble_view_mode
= BUBBLE_VIEW_MODE_GAIA_REAUTH
;
513 case BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN
:
514 *bubble_view_mode
= BUBBLE_VIEW_MODE_PROFILE_CHOOSER
;
515 *tutorial_mode
= TUTORIAL_MODE_CONFIRM_SIGNIN
;
517 case BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR
:
518 *bubble_view_mode
= BUBBLE_VIEW_MODE_PROFILE_CHOOSER
;
519 *tutorial_mode
= TUTORIAL_MODE_SHOW_ERROR
;
521 case BrowserWindow::AVATAR_BUBBLE_MODE_FAST_USER_SWITCH
:
522 *bubble_view_mode
= profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER
;
525 *bubble_view_mode
= profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
;
529 bool ShouldShowWelcomeUpgradeTutorial(
530 Profile
* profile
, TutorialMode tutorial_mode
) {
531 const int show_count
= profile
->GetPrefs()->GetInteger(
532 prefs::kProfileAvatarTutorialShown
);
533 // Do not show the tutorial if user has dismissed it.
534 if (show_count
> signin_ui_util::kUpgradeWelcomeTutorialShowMax
)
537 return tutorial_mode
== TUTORIAL_MODE_WELCOME_UPGRADE
||
538 show_count
!= signin_ui_util::kUpgradeWelcomeTutorialShowMax
;
541 bool ShouldShowRightClickTutorial(Profile
* profile
) {
542 PrefService
* local_state
= g_browser_process
->local_state();
543 const bool dismissed
= local_state
->GetBoolean(
544 prefs::kProfileAvatarRightClickTutorialDismissed
);
546 // Don't show the tutorial if it's already been dismissed or if right-clicking
547 // wouldn't show any targets.
548 return !dismissed
&& HasProfileSwitchTargets(profile
);
551 } // namespace profiles