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/ui/browser.h"
21 #include "chrome/browser/ui/browser_dialogs.h"
22 #include "chrome/browser/ui/profile_chooser_constants.h"
23 #include "chrome/browser/ui/user_manager.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/url_constants.h"
27 #include "components/signin/core/browser/account_reconcilor.h"
28 #include "components/signin/core/common/profile_management_switches.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/user_metrics.h"
33 #include "chrome/browser/ui/browser_finder.h"
34 #include "chrome/browser/ui/browser_list.h"
35 #include "chrome/browser/ui/browser_list_observer.h"
36 #include "chrome/browser/ui/browser_window.h"
37 #include "chrome/browser/ui/startup/startup_browser_creator.h"
38 #endif // !defined (OS_IOS)
40 using base::UserMetricsAction;
41 using content::BrowserThread;
45 const char kNewProfileManagementExperimentInternalName[] =
46 "enable-new-profile-management";
48 // Handles running a callback when a new Browser for the given profile
49 // has been completely created.
50 class BrowserAddedForProfileObserver : public chrome::BrowserListObserver {
52 BrowserAddedForProfileObserver(
54 ProfileManager::CreateCallback callback)
57 DCHECK(!callback_.is_null());
58 BrowserList::AddObserver(this);
60 ~BrowserAddedForProfileObserver() override {}
63 // Overridden from BrowserListObserver:
64 void OnBrowserAdded(Browser* browser) override {
65 if (browser->profile() == profile_) {
66 BrowserList::RemoveObserver(this);
67 callback_.Run(profile_, Profile::CREATE_STATUS_INITIALIZED);
68 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
72 // Profile for which the browser should be opened.
74 ProfileManager::CreateCallback callback_;
76 DISALLOW_COPY_AND_ASSIGN(BrowserAddedForProfileObserver);
79 void OpenBrowserWindowForProfile(
80 ProfileManager::CreateCallback callback,
83 chrome::HostDesktopType desktop_type,
85 Profile::CreateStatus status) {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
88 if (status != Profile::CREATE_STATUS_INITIALIZED)
91 chrome::startup::IsProcessStartup is_process_startup =
92 chrome::startup::IS_NOT_PROCESS_STARTUP;
93 chrome::startup::IsFirstRun is_first_run = chrome::startup::IS_NOT_FIRST_RUN;
95 // If this is a brand new profile, then start a first run window.
97 is_process_startup = chrome::startup::IS_PROCESS_STARTUP;
98 is_first_run = chrome::startup::IS_FIRST_RUN;
101 // If |always_create| is false, and we have a |callback| to run, check
102 // whether a browser already exists so that we can run the callback. We don't
103 // want to rely on the observer listening to OnBrowserSetLastActive in this
104 // case, as you could manually activate an incorrect browser and trigger
106 if (!always_create) {
107 Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
109 browser->window()->Activate();
110 if (!callback.is_null())
111 callback.Run(profile, Profile::CREATE_STATUS_INITIALIZED);
116 // If there is a callback, create an observer to make sure it is only
117 // run when the browser has been completely created. This observer will
118 // delete itself once that happens. This should not leak, because we are
119 // passing |always_create| = true to FindOrCreateNewWindow below, which ends
120 // up calling LaunchBrowser and opens a new window. If for whatever reason
121 // that fails, either something has crashed, or the observer will be cleaned
122 // up when a different browser for this profile is opened.
123 if (!callback.is_null())
124 new BrowserAddedForProfileObserver(profile, callback);
126 // We already dealt with the case when |always_create| was false and a browser
127 // existed, which means that here a browser definitely needs to be created.
128 // Passing true for |always_create| means we won't duplicate the code that
129 // tries to find a browser.
130 profiles::FindOrCreateNewWindowForProfile(
138 // Called after a |guest_profile| is available to be used by the user manager.
139 // Based on the value of |tutorial_mode| we determine a url to be displayed
140 // by the webui and run the |callback|, if it exists. After opening a profile,
141 // perform |profile_open_action|.
142 void OnUserManagerGuestProfileCreated(
143 const base::FilePath& profile_path_to_focus,
144 profiles::UserManagerTutorialMode tutorial_mode,
145 profiles::UserManagerProfileSelected profile_open_action,
146 const base::Callback<void(Profile*, const std::string&)>& callback,
147 Profile* guest_profile,
148 Profile::CreateStatus status) {
149 if (status != Profile::CREATE_STATUS_INITIALIZED || callback.is_null())
152 // Tell the webui which user should be focused.
153 std::string page = chrome::kChromeUIUserManagerURL;
155 if (tutorial_mode == profiles::USER_MANAGER_TUTORIAL_OVERVIEW) {
156 page += profiles::kUserManagerDisplayTutorial;
157 } else if (!profile_path_to_focus.empty()) {
158 const ProfileInfoCache& cache =
159 g_browser_process->profile_manager()->GetProfileInfoCache();
160 size_t index = cache.GetIndexOfProfileWithPath(profile_path_to_focus);
161 if (index != std::string::npos) {
163 page += base::IntToString(index);
165 } else if (profile_open_action ==
166 profiles::USER_MANAGER_SELECT_PROFILE_TASK_MANAGER) {
167 page += profiles::kUserManagerSelectProfileTaskManager;
168 } else if (profile_open_action ==
169 profiles::USER_MANAGER_SELECT_PROFILE_ABOUT_CHROME) {
170 page += profiles::kUserManagerSelectProfileAboutChrome;
171 } else if (profile_open_action ==
172 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_SETTINGS) {
173 page += profiles::kUserManagerSelectProfileChromeSettings;
174 } else if (profile_open_action ==
175 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_MEMORY) {
176 page += profiles::kUserManagerSelectProfileChromeMemory;
178 callback.Run(guest_profile, page);
181 // Updates Chrome services that require notification when
182 // the new_profile_management's status changes.
183 void UpdateServicesWithNewProfileManagementFlag(Profile* profile,
184 bool new_flag_status) {
185 AccountReconcilor* account_reconcilor =
186 AccountReconcilorFactory::GetForProfile(profile);
187 account_reconcilor->OnNewProfileManagementFlagChanged(new_flag_status);
194 // User Manager parameters are prefixed with hash.
195 const char kUserManagerDisplayTutorial[] = "#tutorial";
196 const char kUserManagerSelectProfileTaskManager[] = "#task-manager";
197 const char kUserManagerSelectProfileAboutChrome[] = "#about-chrome";
198 const char kUserManagerSelectProfileChromeSettings[] = "#chrome-settings";
199 const char kUserManagerSelectProfileChromeMemory[] = "#chrome-memory";
201 void FindOrCreateNewWindowForProfile(
203 chrome::startup::IsProcessStartup process_startup,
204 chrome::startup::IsFirstRun is_first_run,
205 chrome::HostDesktopType desktop_type,
206 bool always_create) {
212 if (!always_create) {
213 Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
215 browser->window()->Activate();
220 content::RecordAction(UserMetricsAction("NewWindow"));
221 CommandLine command_line(CommandLine::NO_PROGRAM);
223 StartupBrowserCreator browser_creator;
224 browser_creator.LaunchBrowser(command_line, profile, base::FilePath(),
225 process_startup, is_first_run, &return_code);
226 #endif // defined(OS_IOS)
229 void SwitchToProfile(const base::FilePath& path,
230 chrome::HostDesktopType desktop_type,
232 ProfileManager::CreateCallback callback,
233 ProfileMetrics::ProfileOpen metric) {
234 g_browser_process->profile_manager()->CreateProfileAsync(
236 base::Bind(&OpenBrowserWindowForProfile,
244 ProfileMetrics::LogProfileSwitchUser(metric);
247 void SwitchToGuestProfile(chrome::HostDesktopType desktop_type,
248 ProfileManager::CreateCallback callback) {
249 g_browser_process->profile_manager()->CreateProfileAsync(
250 ProfileManager::GetGuestProfilePath(),
251 base::Bind(&OpenBrowserWindowForProfile,
259 ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_GUEST);
262 void CreateAndSwitchToNewProfile(chrome::HostDesktopType desktop_type,
263 ProfileManager::CreateCallback callback,
264 ProfileMetrics::ProfileAdd metric) {
265 ProfileInfoCache& cache =
266 g_browser_process->profile_manager()->GetProfileInfoCache();
268 int placeholder_avatar_index = profiles::GetPlaceholderAvatarIndex();
269 ProfileManager::CreateMultiProfileAsync(
270 cache.ChooseNameForNewProfile(placeholder_avatar_index),
271 base::UTF8ToUTF16(profiles::GetDefaultAvatarIconUrl(
272 placeholder_avatar_index)),
273 base::Bind(&OpenBrowserWindowForProfile,
279 ProfileMetrics::LogProfileAddNewUser(metric);
282 void GuestBrowserCloseSuccess(const base::FilePath& profile_path) {
283 UserManager::Show(base::FilePath(),
284 profiles::USER_MANAGER_NO_TUTORIAL,
285 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
288 void CloseGuestProfileWindows() {
289 ProfileManager* profile_manager = g_browser_process->profile_manager();
290 Profile* profile = profile_manager->GetProfileByPath(
291 ProfileManager::GetGuestProfilePath());
294 BrowserList::CloseAllBrowsersWithProfile(
295 profile, base::Bind(&GuestBrowserCloseSuccess));
299 void LockBrowserCloseSuccess(const base::FilePath& profile_path) {
300 ProfileInfoCache* cache =
301 &g_browser_process->profile_manager()->GetProfileInfoCache();
303 cache->SetProfileSigninRequiredAtIndex(
304 cache->GetIndexOfProfileWithPath(profile_path), true);
305 chrome::HideTaskManager();
306 UserManager::Show(profile_path,
307 profiles::USER_MANAGER_NO_TUTORIAL,
308 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
311 void LockProfile(Profile* profile) {
314 BrowserList::CloseAllBrowsersWithProfile(
315 profile, base::Bind(&LockBrowserCloseSuccess));
319 bool IsLockAvailable(Profile* profile) {
321 if (!switches::IsNewProfileManagement())
324 const std::string& hosted_domain = profile->GetPrefs()->
325 GetString(prefs::kGoogleServicesHostedDomain);
326 // TODO(mlerman): Prohibit only users who authenticate using SAML. Until then,
327 // prohibited users who use hosted domains (aside from google.com).
328 if (hosted_domain != Profile::kNoHostedDomainFound &&
329 hosted_domain != "google.com") {
333 const ProfileInfoCache& cache =
334 g_browser_process->profile_manager()->GetProfileInfoCache();
335 for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
336 if (cache.ProfileIsSupervisedAtIndex(i))
342 void CreateGuestProfileForUserManager(
343 const base::FilePath& profile_path_to_focus,
344 profiles::UserManagerTutorialMode tutorial_mode,
345 profiles::UserManagerProfileSelected profile_open_action,
346 const base::Callback<void(Profile*, const std::string&)>& callback) {
347 // Create the guest profile, if necessary, and open the User Manager
348 // from the guest profile.
349 g_browser_process->profile_manager()->CreateProfileAsync(
350 ProfileManager::GetGuestProfilePath(),
351 base::Bind(&OnUserManagerGuestProfileCreated,
352 profile_path_to_focus,
361 void ShowUserManagerMaybeWithTutorial(Profile* profile) {
362 // Guest users cannot appear in the User Manager, nor display a tutorial.
363 if (!profile || profile->IsGuestSession()) {
364 UserManager::Show(base::FilePath(),
365 profiles::USER_MANAGER_NO_TUTORIAL,
366 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
369 UserManager::Show(base::FilePath(),
370 profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
371 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
374 void EnableNewProfileManagementPreview(Profile* profile) {
375 #if defined(OS_ANDROID)
378 // TODO(rogerta): instead of setting experiment flags and command line
379 // args, we should set a profile preference.
380 const about_flags::Experiment experiment = {
381 kNewProfileManagementExperimentInternalName,
382 0, // string id for title of experiment
383 0, // string id for description of experiment
384 0, // supported platforms
385 about_flags::Experiment::ENABLE_DISABLE_VALUE,
386 switches::kEnableNewProfileManagement,
387 "", // not used with ENABLE_DISABLE_VALUE type
388 switches::kDisableNewProfileManagement,
389 "", // not used with ENABLE_DISABLE_VALUE type
390 NULL, // not used with ENABLE_DISABLE_VALUE type
393 about_flags::PrefServiceFlagsStorage flags_storage(
394 g_browser_process->local_state());
395 about_flags::SetExperimentEnabled(
397 experiment.NameForChoice(1),
400 switches::EnableNewProfileManagementForTesting(
401 CommandLine::ForCurrentProcess());
402 UserManager::Show(base::FilePath(),
403 profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
404 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
405 UpdateServicesWithNewProfileManagementFlag(profile, true);
409 void DisableNewProfileManagementPreview(Profile* profile) {
410 about_flags::PrefServiceFlagsStorage flags_storage(
411 g_browser_process->local_state());
412 about_flags::SetExperimentEnabled(
414 kNewProfileManagementExperimentInternalName,
416 chrome::AttemptRestart();
417 UpdateServicesWithNewProfileManagementFlag(profile, false);
420 void BubbleViewModeFromAvatarBubbleMode(
421 BrowserWindow::AvatarBubbleMode mode,
422 BubbleViewMode* bubble_view_mode,
423 TutorialMode* tutorial_mode) {
424 *tutorial_mode = TUTORIAL_MODE_NONE;
426 case BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT:
427 *bubble_view_mode = BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
429 case BrowserWindow::AVATAR_BUBBLE_MODE_SIGNIN:
430 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_SIGNIN;
432 case BrowserWindow::AVATAR_BUBBLE_MODE_ADD_ACCOUNT:
433 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT;
435 case BrowserWindow::AVATAR_BUBBLE_MODE_REAUTH:
436 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_REAUTH;
438 case BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN:
439 *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
440 *tutorial_mode = TUTORIAL_MODE_CONFIRM_SIGNIN;
442 case BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR:
443 *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
444 *tutorial_mode = TUTORIAL_MODE_SHOW_ERROR;
447 *bubble_view_mode = profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
451 } // namespace profiles