Cleanup: new common GetProfileSwitcherTextForItem for use on both Win and Mac
[chromium-blink-merge.git] / chrome / browser / profiles / profile_window.cc
blob0080945cadcef8a6ed67deb0fddddb9e764bfb43
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/sync/profile_sync_service.h"
22 #include "chrome/browser/sync/profile_sync_service_factory.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_dialogs.h"
25 #include "chrome/browser/ui/profile_chooser_constants.h"
26 #include "chrome/browser/ui/user_manager.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/common/url_constants.h"
30 #include "components/signin/core/browser/account_reconcilor.h"
31 #include "components/signin/core/browser/account_tracker_service.h"
32 #include "components/signin/core/common/profile_management_switches.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/user_metrics.h"
36 #if defined(ENABLE_EXTENSIONS)
37 #include "chrome/browser/extensions/extension_service.h"
38 #include "extensions/browser/extension_prefs.h"
39 #include "extensions/browser/extension_registry.h"
40 #include "extensions/browser/extension_registry_factory.h"
41 #include "extensions/browser/extension_system.h"
42 #endif // defined(ENABLE_EXTENSIONS)
44 #if !defined(OS_IOS)
45 #include "chrome/browser/ui/browser_finder.h"
46 #include "chrome/browser/ui/browser_list.h"
47 #include "chrome/browser/ui/browser_list_observer.h"
48 #include "chrome/browser/ui/browser_window.h"
49 #include "chrome/browser/ui/startup/startup_browser_creator.h"
50 #endif // !defined (OS_IOS)
52 using base::UserMetricsAction;
53 using content::BrowserThread;
55 namespace {
57 const char kNewProfileManagementExperimentInternalName[] =
58 "enable-new-profile-management";
60 #if defined(ENABLE_EXTENSIONS)
61 void BlockExtensions(Profile* profile) {
62 ExtensionService* extension_service =
63 extensions::ExtensionSystem::Get(profile)->extension_service();
64 extension_service->BlockAllExtensions();
67 void UnblockExtensions(Profile* profile) {
68 ExtensionService* extension_service =
69 extensions::ExtensionSystem::Get(profile)->extension_service();
70 extension_service->UnblockAllExtensions();
72 #endif // defined(ENABLE_EXTENSIONS)
74 // Handles running a callback when a new Browser for the given profile
75 // has been completely created.
76 class BrowserAddedForProfileObserver : public chrome::BrowserListObserver {
77 public:
78 BrowserAddedForProfileObserver(
79 Profile* profile,
80 ProfileManager::CreateCallback callback)
81 : profile_(profile),
82 callback_(callback) {
83 DCHECK(!callback_.is_null());
84 BrowserList::AddObserver(this);
86 ~BrowserAddedForProfileObserver() override {}
88 private:
89 // Overridden from BrowserListObserver:
90 void OnBrowserAdded(Browser* browser) override {
91 if (browser->profile() == profile_) {
92 BrowserList::RemoveObserver(this);
93 callback_.Run(profile_, Profile::CREATE_STATUS_INITIALIZED);
94 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
98 // Profile for which the browser should be opened.
99 Profile* profile_;
100 ProfileManager::CreateCallback callback_;
102 DISALLOW_COPY_AND_ASSIGN(BrowserAddedForProfileObserver);
105 void OpenBrowserWindowForProfile(
106 ProfileManager::CreateCallback callback,
107 bool always_create,
108 bool is_new_profile,
109 chrome::HostDesktopType desktop_type,
110 Profile* profile,
111 Profile::CreateStatus status) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114 if (status != Profile::CREATE_STATUS_INITIALIZED)
115 return;
117 chrome::startup::IsProcessStartup is_process_startup =
118 chrome::startup::IS_NOT_PROCESS_STARTUP;
119 chrome::startup::IsFirstRun is_first_run = chrome::startup::IS_NOT_FIRST_RUN;
121 // If this is a brand new profile, then start a first run window.
122 if (is_new_profile) {
123 is_process_startup = chrome::startup::IS_PROCESS_STARTUP;
124 is_first_run = chrome::startup::IS_FIRST_RUN;
127 #if defined(ENABLE_EXTENSIONS)
128 // The signin bit will still be set if the profile is being unlocked and the
129 // browser window for it is opening. As part of this unlock process, unblock
130 // all the extensions.
131 const ProfileInfoCache& cache =
132 g_browser_process->profile_manager()->GetProfileInfoCache();
133 int index = cache.GetIndexOfProfileWithPath(profile->GetPath());
134 if (!profile->IsGuestSession() &&
135 cache.ProfileIsSigninRequiredAtIndex(index)) {
136 UnblockExtensions(profile);
138 #endif // defined(ENABLE_EXTENSIONS)
140 // If |always_create| is false, and we have a |callback| to run, check
141 // whether a browser already exists so that we can run the callback. We don't
142 // want to rely on the observer listening to OnBrowserSetLastActive in this
143 // case, as you could manually activate an incorrect browser and trigger
144 // a false positive.
145 if (!always_create) {
146 Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
147 if (browser) {
148 browser->window()->Activate();
149 if (!callback.is_null())
150 callback.Run(profile, Profile::CREATE_STATUS_INITIALIZED);
151 return;
155 // If there is a callback, create an observer to make sure it is only
156 // run when the browser has been completely created. This observer will
157 // delete itself once that happens. This should not leak, because we are
158 // passing |always_create| = true to FindOrCreateNewWindow below, which ends
159 // up calling LaunchBrowser and opens a new window. If for whatever reason
160 // that fails, either something has crashed, or the observer will be cleaned
161 // up when a different browser for this profile is opened.
162 if (!callback.is_null())
163 new BrowserAddedForProfileObserver(profile, callback);
165 // We already dealt with the case when |always_create| was false and a browser
166 // existed, which means that here a browser definitely needs to be created.
167 // Passing true for |always_create| means we won't duplicate the code that
168 // tries to find a browser.
169 profiles::FindOrCreateNewWindowForProfile(
170 profile,
171 is_process_startup,
172 is_first_run,
173 desktop_type,
174 true);
177 // Called after a |system_profile| is available to be used by the user manager.
178 // Based on the value of |tutorial_mode| we determine a url to be displayed
179 // by the webui and run the |callback|, if it exists. After opening a profile,
180 // perform |profile_open_action|.
181 void OnUserManagerSystemProfileCreated(
182 const base::FilePath& profile_path_to_focus,
183 profiles::UserManagerTutorialMode tutorial_mode,
184 profiles::UserManagerProfileSelected profile_open_action,
185 const base::Callback<void(Profile*, const std::string&)>& callback,
186 Profile* system_profile,
187 Profile::CreateStatus status) {
188 if (status != Profile::CREATE_STATUS_INITIALIZED || callback.is_null())
189 return;
191 // Tell the webui which user should be focused.
192 std::string page = chrome::kChromeUIUserManagerURL;
194 if (tutorial_mode == profiles::USER_MANAGER_TUTORIAL_OVERVIEW) {
195 page += profiles::kUserManagerDisplayTutorial;
196 } else if (!profile_path_to_focus.empty()) {
197 const ProfileInfoCache& cache =
198 g_browser_process->profile_manager()->GetProfileInfoCache();
199 size_t index = cache.GetIndexOfProfileWithPath(profile_path_to_focus);
200 if (index != std::string::npos) {
201 page += "#";
202 page += base::IntToString(index);
204 } else if (profile_open_action ==
205 profiles::USER_MANAGER_SELECT_PROFILE_TASK_MANAGER) {
206 page += profiles::kUserManagerSelectProfileTaskManager;
207 } else if (profile_open_action ==
208 profiles::USER_MANAGER_SELECT_PROFILE_ABOUT_CHROME) {
209 page += profiles::kUserManagerSelectProfileAboutChrome;
210 } else if (profile_open_action ==
211 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_SETTINGS) {
212 page += profiles::kUserManagerSelectProfileChromeSettings;
213 } else if (profile_open_action ==
214 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_MEMORY) {
215 page += profiles::kUserManagerSelectProfileChromeMemory;
216 } else if (profile_open_action ==
217 profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER) {
218 page += profiles::kUserManagerSelectProfileAppLauncher;
220 callback.Run(system_profile, page);
223 // Updates Chrome services that require notification when
224 // the new_profile_management's status changes.
225 void UpdateServicesWithNewProfileManagementFlag(Profile* profile,
226 bool new_flag_status) {
227 AccountReconcilor* account_reconcilor =
228 AccountReconcilorFactory::GetForProfile(profile);
229 account_reconcilor->OnNewProfileManagementFlagChanged(new_flag_status);
232 } // namespace
234 namespace profiles {
236 // User Manager parameters are prefixed with hash.
237 const char kUserManagerDisplayTutorial[] = "#tutorial";
238 const char kUserManagerSelectProfileTaskManager[] = "#task-manager";
239 const char kUserManagerSelectProfileAboutChrome[] = "#about-chrome";
240 const char kUserManagerSelectProfileChromeSettings[] = "#chrome-settings";
241 const char kUserManagerSelectProfileChromeMemory[] = "#chrome-memory";
242 const char kUserManagerSelectProfileAppLauncher[] = "#app-launcher";
244 void FindOrCreateNewWindowForProfile(
245 Profile* profile,
246 chrome::startup::IsProcessStartup process_startup,
247 chrome::startup::IsFirstRun is_first_run,
248 chrome::HostDesktopType desktop_type,
249 bool always_create) {
250 #if defined(OS_IOS)
251 NOTREACHED();
252 #else
253 DCHECK(profile);
255 if (!always_create) {
256 Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
257 if (browser) {
258 browser->window()->Activate();
259 return;
263 content::RecordAction(UserMetricsAction("NewWindow"));
264 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
265 StartupBrowserCreator browser_creator;
266 browser_creator.LaunchBrowser(
267 command_line, profile, base::FilePath(), process_startup, is_first_run);
268 #endif // defined(OS_IOS)
271 void SwitchToProfile(const base::FilePath& path,
272 chrome::HostDesktopType desktop_type,
273 bool always_create,
274 ProfileManager::CreateCallback callback,
275 ProfileMetrics::ProfileOpen metric) {
276 ProfileMetrics::LogProfileSwitch(metric,
277 g_browser_process->profile_manager(),
278 path);
279 g_browser_process->profile_manager()->CreateProfileAsync(
280 path,
281 base::Bind(&OpenBrowserWindowForProfile,
282 callback,
283 always_create,
284 false,
285 desktop_type),
286 base::string16(),
287 base::string16(),
288 std::string());
291 void SwitchToGuestProfile(chrome::HostDesktopType desktop_type,
292 ProfileManager::CreateCallback callback) {
293 const base::FilePath& path = ProfileManager::GetGuestProfilePath();
294 ProfileMetrics::LogProfileSwitch(ProfileMetrics::SWITCH_PROFILE_GUEST,
295 g_browser_process->profile_manager(),
296 path);
297 g_browser_process->profile_manager()->CreateProfileAsync(
298 path,
299 base::Bind(&OpenBrowserWindowForProfile,
300 callback,
301 false,
302 false,
303 desktop_type),
304 base::string16(),
305 base::string16(),
306 std::string());
309 bool HasProfileSwitchTargets(Profile* profile) {
310 size_t min_profiles = profile->IsGuestSession() ? 1 : 2;
311 size_t number_of_profiles =
312 g_browser_process->profile_manager()->GetNumberOfProfiles();
313 return number_of_profiles < min_profiles;
316 void CreateAndSwitchToNewProfile(chrome::HostDesktopType desktop_type,
317 ProfileManager::CreateCallback callback,
318 ProfileMetrics::ProfileAdd metric) {
319 ProfileInfoCache& cache =
320 g_browser_process->profile_manager()->GetProfileInfoCache();
322 int placeholder_avatar_index = profiles::GetPlaceholderAvatarIndex();
323 ProfileManager::CreateMultiProfileAsync(
324 cache.ChooseNameForNewProfile(placeholder_avatar_index),
325 base::UTF8ToUTF16(profiles::GetDefaultAvatarIconUrl(
326 placeholder_avatar_index)),
327 base::Bind(&OpenBrowserWindowForProfile,
328 callback,
329 true,
330 true,
331 desktop_type),
332 std::string());
333 ProfileMetrics::LogProfileAddNewUser(metric);
336 void GuestBrowserCloseSuccess(const base::FilePath& profile_path) {
337 UserManager::Show(base::FilePath(),
338 profiles::USER_MANAGER_NO_TUTORIAL,
339 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
342 void CloseGuestProfileWindows() {
343 ProfileManager* profile_manager = g_browser_process->profile_manager();
344 Profile* profile = profile_manager->GetProfileByPath(
345 ProfileManager::GetGuestProfilePath());
347 if (profile) {
348 BrowserList::CloseAllBrowsersWithProfile(
349 profile, base::Bind(&GuestBrowserCloseSuccess));
353 void LockBrowserCloseSuccess(const base::FilePath& profile_path) {
354 ProfileManager* profile_manager = g_browser_process->profile_manager();
355 ProfileInfoCache* cache = &profile_manager->GetProfileInfoCache();
357 cache->SetProfileSigninRequiredAtIndex(
358 cache->GetIndexOfProfileWithPath(profile_path), true);
360 #if defined(ENABLE_EXTENSIONS)
361 // Profile guaranteed to exist for it to have been locked.
362 BlockExtensions(profile_manager->GetProfileByPath(profile_path));
363 #endif // defined(ENABLE_EXTENSIONS)
365 chrome::HideTaskManager();
366 UserManager::Show(profile_path,
367 profiles::USER_MANAGER_NO_TUTORIAL,
368 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
371 void LockProfile(Profile* profile) {
372 DCHECK(profile);
373 if (profile) {
374 BrowserList::CloseAllBrowsersWithProfile(
375 profile, base::Bind(&LockBrowserCloseSuccess));
379 bool IsLockAvailable(Profile* profile) {
380 DCHECK(profile);
381 if (!switches::IsNewProfileManagement())
382 return false;
384 if (profile->IsGuestSession())
385 return false;
387 const ProfileInfoCache& cache =
388 g_browser_process->profile_manager()->GetProfileInfoCache();
389 std::string hosted_domain = profile->GetPrefs()->
390 GetString(prefs::kGoogleServicesHostedDomain);
391 // TODO(mlerman): After one release remove any hosted_domain reference to the
392 // pref, since all users will have this in the AccountTrackerService.
393 if (hosted_domain.empty()) {
394 AccountTrackerService* account_tracker =
395 AccountTrackerServiceFactory::GetForProfile(profile);
396 int profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
397 hosted_domain = account_tracker->FindAccountInfoByEmail(base::UTF16ToUTF8(
398 cache.GetUserNameOfProfileAtIndex(profile_index))).hosted_domain;
400 // TODO(mlerman): Prohibit only users who authenticate using SAML. Until then,
401 // prohibited users who use hosted domains (aside from google.com).
402 if (hosted_domain != Profile::kNoHostedDomainFound &&
403 hosted_domain != "google.com") {
404 return false;
407 for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
408 if (cache.ProfileIsSupervisedAtIndex(i))
409 return true;
411 return false;
414 void CreateSystemProfileForUserManager(
415 const base::FilePath& profile_path_to_focus,
416 profiles::UserManagerTutorialMode tutorial_mode,
417 profiles::UserManagerProfileSelected profile_open_action,
418 const base::Callback<void(Profile*, const std::string&)>& callback) {
419 // Create the system profile, if necessary, and open the User Manager
420 // from the system profile.
421 g_browser_process->profile_manager()->CreateProfileAsync(
422 ProfileManager::GetSystemProfilePath(),
423 base::Bind(&OnUserManagerSystemProfileCreated,
424 profile_path_to_focus,
425 tutorial_mode,
426 profile_open_action,
427 callback),
428 base::string16(),
429 base::string16(),
430 std::string());
433 void ShowUserManagerMaybeWithTutorial(Profile* profile) {
434 // Guest users cannot appear in the User Manager, nor display a tutorial.
435 if (!profile || profile->IsGuestSession()) {
436 UserManager::Show(base::FilePath(),
437 profiles::USER_MANAGER_NO_TUTORIAL,
438 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
439 return;
441 UserManager::Show(base::FilePath(),
442 profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
443 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
446 void EnableNewProfileManagementPreview(Profile* profile) {
447 #if defined(OS_ANDROID)
448 NOTREACHED();
449 #else
450 // TODO(rogerta): instead of setting experiment flags and command line
451 // args, we should set a profile preference.
452 const about_flags::Experiment experiment = {
453 kNewProfileManagementExperimentInternalName,
454 0, // string id for title of experiment
455 0, // string id for description of experiment
456 0, // supported platforms
457 about_flags::Experiment::ENABLE_DISABLE_VALUE,
458 switches::kEnableNewProfileManagement,
459 "", // not used with ENABLE_DISABLE_VALUE type
460 switches::kDisableNewProfileManagement,
461 "", // not used with ENABLE_DISABLE_VALUE type
462 NULL, // not used with ENABLE_DISABLE_VALUE type
465 about_flags::PrefServiceFlagsStorage flags_storage(
466 g_browser_process->local_state());
467 about_flags::SetExperimentEnabled(
468 &flags_storage,
469 experiment.NameForChoice(1),
470 true);
472 switches::EnableNewProfileManagementForTesting(
473 base::CommandLine::ForCurrentProcess());
474 UserManager::Show(base::FilePath(),
475 profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
476 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
477 UpdateServicesWithNewProfileManagementFlag(profile, true);
478 #endif
481 void DisableNewProfileManagementPreview(Profile* profile) {
482 about_flags::PrefServiceFlagsStorage flags_storage(
483 g_browser_process->local_state());
484 about_flags::SetExperimentEnabled(
485 &flags_storage,
486 kNewProfileManagementExperimentInternalName,
487 false);
488 chrome::AttemptRestart();
489 UpdateServicesWithNewProfileManagementFlag(profile, false);
492 void BubbleViewModeFromAvatarBubbleMode(
493 BrowserWindow::AvatarBubbleMode mode,
494 BubbleViewMode* bubble_view_mode,
495 TutorialMode* tutorial_mode) {
496 *tutorial_mode = TUTORIAL_MODE_NONE;
497 switch (mode) {
498 case BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT:
499 *bubble_view_mode = BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
500 return;
501 case BrowserWindow::AVATAR_BUBBLE_MODE_SIGNIN:
502 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_SIGNIN;
503 return;
504 case BrowserWindow::AVATAR_BUBBLE_MODE_ADD_ACCOUNT:
505 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT;
506 return;
507 case BrowserWindow::AVATAR_BUBBLE_MODE_REAUTH:
508 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_REAUTH;
509 return;
510 case BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN:
511 *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
512 *tutorial_mode = TUTORIAL_MODE_CONFIRM_SIGNIN;
513 return;
514 case BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR:
515 *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
516 *tutorial_mode = TUTORIAL_MODE_SHOW_ERROR;
517 return;
518 case BrowserWindow::AVATAR_BUBBLE_MODE_FAST_USER_SWITCH:
519 *bubble_view_mode = profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER;
520 return;
521 default:
522 *bubble_view_mode = profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
526 } // namespace profiles