Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / profiles / profile_window.cc
blob2f2ca80b81729afd3ef607e345c01c1ca2b1f310
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)
47 #if !defined(OS_IOS)
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;
58 namespace {
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 {
80 public:
81 BrowserAddedForProfileObserver(
82 Profile* profile,
83 ProfileManager::CreateCallback callback)
84 : profile_(profile),
85 callback_(callback) {
86 DCHECK(!callback_.is_null());
87 BrowserList::AddObserver(this);
89 ~BrowserAddedForProfileObserver() override {}
91 private:
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.
102 Profile* profile_;
103 ProfileManager::CreateCallback callback_;
105 DISALLOW_COPY_AND_ASSIGN(BrowserAddedForProfileObserver);
108 void OpenBrowserWindowForProfile(
109 ProfileManager::CreateCallback callback,
110 bool always_create,
111 bool is_new_profile,
112 chrome::HostDesktopType desktop_type,
113 Profile* profile,
114 Profile::CreateStatus status) {
115 DCHECK_CURRENTLY_ON(BrowserThread::UI);
117 if (status != Profile::CREATE_STATUS_INITIALIZED)
118 return;
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
147 // a false positive.
148 if (!always_create) {
149 Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
150 if (browser) {
151 browser->window()->Activate();
152 if (!callback.is_null())
153 callback.Run(profile, Profile::CREATE_STATUS_INITIALIZED);
154 return;
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(
173 profile,
174 is_process_startup,
175 is_first_run,
176 desktop_type,
177 true);
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())
192 return;
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) {
204 page += "#";
205 page += base::SizeTToString(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);
235 } // namespace
237 namespace profiles {
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 base::FilePath GetPathOfProfileWithEmail(ProfileManager* profile_manager,
248 const std::string& email) {
249 base::string16 profile_email = base::UTF8ToUTF16(email);
250 std::vector<ProfileAttributesEntry*> entries =
251 profile_manager->GetProfileInfoCache().GetAllProfilesAttributes();
252 for (ProfileAttributesEntry* entry : entries) {
253 if (entry->GetUserName() == profile_email)
254 return entry->GetPath();
256 return base::FilePath();
259 void FindOrCreateNewWindowForProfile(
260 Profile* profile,
261 chrome::startup::IsProcessStartup process_startup,
262 chrome::startup::IsFirstRun is_first_run,
263 chrome::HostDesktopType desktop_type,
264 bool always_create) {
265 #if defined(OS_IOS)
266 NOTREACHED();
267 #else
268 DCHECK(profile);
270 if (!always_create) {
271 Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
272 if (browser) {
273 browser->window()->Activate();
274 return;
278 content::RecordAction(UserMetricsAction("NewWindow"));
279 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
280 StartupBrowserCreator browser_creator;
281 browser_creator.LaunchBrowser(
282 command_line, profile, base::FilePath(), process_startup, is_first_run);
283 #endif // defined(OS_IOS)
286 void SwitchToProfile(const base::FilePath& path,
287 chrome::HostDesktopType desktop_type,
288 bool always_create,
289 ProfileManager::CreateCallback callback,
290 ProfileMetrics::ProfileOpen metric) {
291 ProfileMetrics::LogProfileSwitch(metric,
292 g_browser_process->profile_manager(),
293 path);
294 g_browser_process->profile_manager()->CreateProfileAsync(
295 path,
296 base::Bind(&OpenBrowserWindowForProfile,
297 callback,
298 always_create,
299 false,
300 desktop_type),
301 base::string16(),
302 base::string16(),
303 std::string());
306 void SwitchToGuestProfile(chrome::HostDesktopType desktop_type,
307 ProfileManager::CreateCallback callback) {
308 const base::FilePath& path = ProfileManager::GetGuestProfilePath();
309 ProfileMetrics::LogProfileSwitch(ProfileMetrics::SWITCH_PROFILE_GUEST,
310 g_browser_process->profile_manager(),
311 path);
312 g_browser_process->profile_manager()->CreateProfileAsync(
313 path,
314 base::Bind(&OpenBrowserWindowForProfile,
315 callback,
316 false,
317 false,
318 desktop_type),
319 base::string16(),
320 base::string16(),
321 std::string());
324 bool HasProfileSwitchTargets(Profile* profile) {
325 size_t min_profiles = profile->IsGuestSession() ? 1 : 2;
326 size_t number_of_profiles =
327 g_browser_process->profile_manager()->GetNumberOfProfiles();
328 return number_of_profiles >= min_profiles;
331 void CreateAndSwitchToNewProfile(chrome::HostDesktopType desktop_type,
332 ProfileManager::CreateCallback callback,
333 ProfileMetrics::ProfileAdd metric) {
334 ProfileInfoCache& cache =
335 g_browser_process->profile_manager()->GetProfileInfoCache();
337 int placeholder_avatar_index = profiles::GetPlaceholderAvatarIndex();
338 ProfileManager::CreateMultiProfileAsync(
339 cache.ChooseNameForNewProfile(placeholder_avatar_index),
340 base::UTF8ToUTF16(profiles::GetDefaultAvatarIconUrl(
341 placeholder_avatar_index)),
342 base::Bind(&OpenBrowserWindowForProfile,
343 callback,
344 true,
345 true,
346 desktop_type),
347 std::string());
348 ProfileMetrics::LogProfileAddNewUser(metric);
351 void GuestBrowserCloseSuccess(const base::FilePath& profile_path) {
352 UserManager::Show(base::FilePath(),
353 profiles::USER_MANAGER_NO_TUTORIAL,
354 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
357 void CloseGuestProfileWindows() {
358 ProfileManager* profile_manager = g_browser_process->profile_manager();
359 Profile* profile = profile_manager->GetProfileByPath(
360 ProfileManager::GetGuestProfilePath());
362 if (profile) {
363 BrowserList::CloseAllBrowsersWithProfile(
364 profile, base::Bind(&GuestBrowserCloseSuccess));
368 void LockBrowserCloseSuccess(const base::FilePath& profile_path) {
369 ProfileManager* profile_manager = g_browser_process->profile_manager();
370 ProfileInfoCache* cache = &profile_manager->GetProfileInfoCache();
372 cache->SetProfileSigninRequiredAtIndex(
373 cache->GetIndexOfProfileWithPath(profile_path), true);
375 #if defined(ENABLE_EXTENSIONS)
376 // Profile guaranteed to exist for it to have been locked.
377 BlockExtensions(profile_manager->GetProfileByPath(profile_path));
378 #endif // defined(ENABLE_EXTENSIONS)
380 chrome::HideTaskManager();
381 UserManager::Show(profile_path,
382 profiles::USER_MANAGER_NO_TUTORIAL,
383 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
386 void LockProfile(Profile* profile) {
387 DCHECK(profile);
388 if (profile) {
389 BrowserList::CloseAllBrowsersWithProfile(
390 profile, base::Bind(&LockBrowserCloseSuccess));
394 bool IsLockAvailable(Profile* profile) {
395 DCHECK(profile);
396 if (!switches::IsNewProfileManagement())
397 return false;
399 if (profile->IsGuestSession() || profile->IsSystemProfile())
400 return false;
402 std::string hosted_domain = profile->GetPrefs()->
403 GetString(prefs::kGoogleServicesHostedDomain);
404 // TODO(mlerman): After one release remove any hosted_domain reference to the
405 // pref, since all users will have this in the AccountTrackerService.
406 if (hosted_domain.empty()) {
407 AccountTrackerService* account_tracker =
408 AccountTrackerServiceFactory::GetForProfile(profile);
409 std::string account_id =
410 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedAccountId();
411 hosted_domain = account_tracker->GetAccountInfo(account_id).hosted_domain;
413 // TODO(mlerman): Prohibit only users who authenticate using SAML. Until then,
414 // prohibited users who use hosted domains (aside from google.com).
415 if (hosted_domain != Profile::kNoHostedDomainFound &&
416 hosted_domain != "google.com") {
417 return false;
420 const ProfileInfoCache& cache =
421 g_browser_process->profile_manager()->GetProfileInfoCache();
422 for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
423 if (cache.ProfileIsSupervisedAtIndex(i))
424 return true;
426 return false;
429 void CreateSystemProfileForUserManager(
430 const base::FilePath& profile_path_to_focus,
431 profiles::UserManagerTutorialMode tutorial_mode,
432 profiles::UserManagerProfileSelected profile_open_action,
433 const base::Callback<void(Profile*, const std::string&)>& callback) {
434 // Create the system profile, if necessary, and open the User Manager
435 // from the system profile.
436 g_browser_process->profile_manager()->CreateProfileAsync(
437 ProfileManager::GetSystemProfilePath(),
438 base::Bind(&OnUserManagerSystemProfileCreated,
439 profile_path_to_focus,
440 tutorial_mode,
441 profile_open_action,
442 callback),
443 base::string16(),
444 base::string16(),
445 std::string());
448 void ShowUserManagerMaybeWithTutorial(Profile* profile) {
449 // Guest users cannot appear in the User Manager, nor display a tutorial.
450 if (!profile || profile->IsGuestSession()) {
451 UserManager::Show(base::FilePath(),
452 profiles::USER_MANAGER_NO_TUTORIAL,
453 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
454 return;
456 UserManager::Show(base::FilePath(),
457 profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
458 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
461 void EnableNewProfileManagementPreview(Profile* profile) {
462 #if defined(OS_ANDROID)
463 NOTREACHED();
464 #else
465 // TODO(rogerta): instead of setting experiment flags and command line
466 // args, we should set a profile preference.
467 const about_flags::Experiment experiment = {
468 kNewProfileManagementExperimentInternalName,
469 0, // string id for title of experiment
470 0, // string id for description of experiment
471 0, // supported platforms
472 about_flags::Experiment::ENABLE_DISABLE_VALUE,
473 switches::kEnableNewProfileManagement,
474 "", // not used with ENABLE_DISABLE_VALUE type
475 switches::kDisableNewProfileManagement,
476 "", // not used with ENABLE_DISABLE_VALUE type
477 NULL, // not used with ENABLE_DISABLE_VALUE type
480 about_flags::PrefServiceFlagsStorage flags_storage(
481 g_browser_process->local_state());
482 about_flags::SetExperimentEnabled(
483 &flags_storage,
484 experiment.NameForChoice(1),
485 true);
487 switches::EnableNewProfileManagementForTesting(
488 base::CommandLine::ForCurrentProcess());
489 UserManager::Show(base::FilePath(),
490 profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
491 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
492 UpdateServicesWithNewProfileManagementFlag(profile, true);
493 #endif
496 void DisableNewProfileManagementPreview(Profile* profile) {
497 about_flags::PrefServiceFlagsStorage flags_storage(
498 g_browser_process->local_state());
499 about_flags::SetExperimentEnabled(
500 &flags_storage,
501 kNewProfileManagementExperimentInternalName,
502 false);
503 chrome::AttemptRestart();
504 UpdateServicesWithNewProfileManagementFlag(profile, false);
507 void BubbleViewModeFromAvatarBubbleMode(
508 BrowserWindow::AvatarBubbleMode mode,
509 BubbleViewMode* bubble_view_mode,
510 TutorialMode* tutorial_mode) {
511 *tutorial_mode = TUTORIAL_MODE_NONE;
512 switch (mode) {
513 case BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT:
514 *bubble_view_mode = BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
515 return;
516 case BrowserWindow::AVATAR_BUBBLE_MODE_SIGNIN:
517 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_SIGNIN;
518 return;
519 case BrowserWindow::AVATAR_BUBBLE_MODE_ADD_ACCOUNT:
520 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT;
521 return;
522 case BrowserWindow::AVATAR_BUBBLE_MODE_REAUTH:
523 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_REAUTH;
524 return;
525 case BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN:
526 *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
527 *tutorial_mode = TUTORIAL_MODE_CONFIRM_SIGNIN;
528 return;
529 case BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR:
530 *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
531 *tutorial_mode = TUTORIAL_MODE_SHOW_ERROR;
532 return;
533 case BrowserWindow::AVATAR_BUBBLE_MODE_FAST_USER_SWITCH:
534 *bubble_view_mode = profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER;
535 return;
536 default:
537 *bubble_view_mode = profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
541 bool ShouldShowWelcomeUpgradeTutorial(
542 Profile* profile, TutorialMode tutorial_mode) {
543 const int show_count = profile->GetPrefs()->GetInteger(
544 prefs::kProfileAvatarTutorialShown);
545 // Do not show the tutorial if user has dismissed it.
546 if (show_count > signin_ui_util::kUpgradeWelcomeTutorialShowMax)
547 return false;
549 return tutorial_mode == TUTORIAL_MODE_WELCOME_UPGRADE ||
550 show_count != signin_ui_util::kUpgradeWelcomeTutorialShowMax;
553 bool ShouldShowRightClickTutorial(Profile* profile) {
554 PrefService* local_state = g_browser_process->local_state();
555 const bool dismissed = local_state->GetBoolean(
556 prefs::kProfileAvatarRightClickTutorialDismissed);
558 // Don't show the tutorial if it's already been dismissed or if right-clicking
559 // wouldn't show any targets.
560 return !dismissed && HasProfileSwitchTargets(profile);
563 } // namespace profiles