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/ui/browser.h"
20 #include "chrome/browser/ui/browser_dialogs.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/common/url_constants.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/user_metrics.h"
28 #include "chrome/browser/ui/browser_finder.h"
29 #include "chrome/browser/ui/browser_list.h"
30 #include "chrome/browser/ui/browser_list_observer.h"
31 #include "chrome/browser/ui/browser_window.h"
32 #include "chrome/browser/ui/startup/startup_browser_creator.h"
33 #endif // !defined (OS_IOS)
35 using base::UserMetricsAction
;
36 using content::BrowserThread
;
40 const char kNewProfileManagementExperimentInternalName
[] =
41 "enable-new-profile-management";
43 // Handles running a callback when a new Browser for the given profile
44 // has been completely created.
45 class BrowserAddedForProfileObserver
: public chrome::BrowserListObserver
{
47 BrowserAddedForProfileObserver(
49 profiles::ProfileSwitchingDoneCallback callback
)
52 DCHECK(!callback_
.is_null());
53 BrowserList::AddObserver(this);
55 virtual ~BrowserAddedForProfileObserver() {
59 // Overridden from BrowserListObserver:
60 virtual void OnBrowserAdded(Browser
* browser
) OVERRIDE
{
61 if (browser
->profile() == profile_
) {
62 BrowserList::RemoveObserver(this);
64 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
68 // Profile for which the browser should be opened.
70 profiles::ProfileSwitchingDoneCallback callback_
;
72 DISALLOW_COPY_AND_ASSIGN(BrowserAddedForProfileObserver
);
75 void OpenBrowserWindowForProfile(
76 profiles::ProfileSwitchingDoneCallback callback
,
79 chrome::HostDesktopType desktop_type
,
81 Profile::CreateStatus status
) {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
84 if (status
!= Profile::CREATE_STATUS_INITIALIZED
)
87 chrome::startup::IsProcessStartup is_process_startup
=
88 chrome::startup::IS_NOT_PROCESS_STARTUP
;
89 chrome::startup::IsFirstRun is_first_run
= chrome::startup::IS_NOT_FIRST_RUN
;
91 // If this is a brand new profile, then start a first run window.
93 is_process_startup
= chrome::startup::IS_PROCESS_STARTUP
;
94 is_first_run
= chrome::startup::IS_FIRST_RUN
;
97 // If |always_create| is false, and we have a |callback| to run, check
98 // whether a browser already exists so that we can run the callback. We don't
99 // want to rely on the observer listening to OnBrowserSetLastActive in this
100 // case, as you could manually activate an incorrect browser and trigger
102 if (!always_create
) {
103 Browser
* browser
= chrome::FindTabbedBrowser(profile
, false, desktop_type
);
105 browser
->window()->Activate();
106 if (!callback
.is_null())
112 // If there is a callback, create an observer to make sure it is only
113 // run when the browser has been completely created. This observer will
114 // delete itself once that happens. This should not leak, because we are
115 // passing |always_create| = true to FindOrCreateNewWindow below, which ends
116 // up calling LaunchBrowser and opens a new window. If for whatever reason
117 // that fails, either something has crashed, or the observer will be cleaned
118 // up when a different browser for this profile is opened.
119 if (!callback
.is_null())
120 new BrowserAddedForProfileObserver(profile
, callback
);
122 // We already dealt with the case when |always_create| was false and a browser
123 // existed, which means that here a browser definitely needs to be created.
124 // Passing true for |always_create| means we won't duplicate the code that
125 // tries to find a browser.
126 profiles::FindOrCreateNewWindowForProfile(
134 // Called after a |guest_profile| is available to be used by the user manager.
135 // Based on the value of |tutorial_mode| we determine a url to be displayed
136 // by the webui and run the |callback|, if it exists.
137 void OnUserManagerGuestProfileCreated(
138 const base::FilePath
& profile_path_to_focus
,
139 profiles::UserManagerTutorialMode tutorial_mode
,
140 const base::Callback
<void(Profile
*, const std::string
&)>& callback
,
141 Profile
* guest_profile
,
142 Profile::CreateStatus status
) {
143 if (status
!= Profile::CREATE_STATUS_INITIALIZED
|| callback
.is_null())
146 // Tell the webui which user should be focused.
147 std::string page
= chrome::kChromeUIUserManagerURL
;
149 if (tutorial_mode
== profiles::USER_MANAGER_TUTORIAL_OVERVIEW
) {
151 } else if (!profile_path_to_focus
.empty()) {
152 const ProfileInfoCache
& cache
=
153 g_browser_process
->profile_manager()->GetProfileInfoCache();
154 size_t index
= cache
.GetIndexOfProfileWithPath(profile_path_to_focus
);
155 if (index
!= std::string::npos
) {
157 page
+= base::IntToString(index
);
161 callback
.Run(guest_profile
, page
);
168 void FindOrCreateNewWindowForProfile(
170 chrome::startup::IsProcessStartup process_startup
,
171 chrome::startup::IsFirstRun is_first_run
,
172 chrome::HostDesktopType desktop_type
,
173 bool always_create
) {
179 if (!always_create
) {
180 Browser
* browser
= chrome::FindTabbedBrowser(profile
, false, desktop_type
);
182 browser
->window()->Activate();
187 content::RecordAction(UserMetricsAction("NewWindow"));
188 CommandLine
command_line(CommandLine::NO_PROGRAM
);
190 StartupBrowserCreator browser_creator
;
191 browser_creator
.LaunchBrowser(command_line
, profile
, base::FilePath(),
192 process_startup
, is_first_run
, &return_code
);
193 #endif // defined(OS_IOS)
196 void SwitchToProfile(const base::FilePath
& path
,
197 chrome::HostDesktopType desktop_type
,
199 ProfileSwitchingDoneCallback callback
,
200 ProfileMetrics::ProfileOpen metric
) {
201 g_browser_process
->profile_manager()->CreateProfileAsync(
203 base::Bind(&OpenBrowserWindowForProfile
,
211 ProfileMetrics::LogProfileSwitchUser(metric
);
214 void SwitchToGuestProfile(chrome::HostDesktopType desktop_type
,
215 ProfileSwitchingDoneCallback callback
) {
216 g_browser_process
->profile_manager()->CreateProfileAsync(
217 ProfileManager::GetGuestProfilePath(),
218 base::Bind(&OpenBrowserWindowForProfile
,
226 ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_GUEST
);
229 void CreateAndSwitchToNewProfile(chrome::HostDesktopType desktop_type
,
230 ProfileSwitchingDoneCallback callback
,
231 ProfileMetrics::ProfileAdd metric
) {
232 ProfileInfoCache
& cache
=
233 g_browser_process
->profile_manager()->GetProfileInfoCache();
235 int placeholder_avatar_index
= profiles::GetPlaceholderAvatarIndex();
236 ProfileManager::CreateMultiProfileAsync(
237 cache
.ChooseNameForNewProfile(placeholder_avatar_index
),
238 base::UTF8ToUTF16(profiles::GetDefaultAvatarIconUrl(
239 placeholder_avatar_index
)),
240 base::Bind(&OpenBrowserWindowForProfile
,
246 ProfileMetrics::LogProfileAddNewUser(metric
);
249 void CloseGuestProfileWindows() {
250 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
251 Profile
* profile
= profile_manager
->GetProfileByPath(
252 ProfileManager::GetGuestProfilePath());
255 BrowserList::CloseAllBrowsersWithProfile(profile
);
259 void LockProfile(Profile
* profile
) {
261 ProfileInfoCache
& cache
=
262 g_browser_process
->profile_manager()->GetProfileInfoCache();
264 size_t index
= cache
.GetIndexOfProfileWithPath(profile
->GetPath());
265 cache
.SetProfileSigninRequiredAtIndex(index
, true);
266 chrome::ShowUserManager(profile
->GetPath());
267 BrowserList::CloseAllBrowsersWithProfile(profile
);
270 void CreateGuestProfileForUserManager(
271 const base::FilePath
& profile_path_to_focus
,
272 profiles::UserManagerTutorialMode tutorial_mode
,
273 const base::Callback
<void(Profile
*, const std::string
&)>& callback
) {
274 // Create the guest profile, if necessary, and open the User Manager
275 // from the guest profile.
276 g_browser_process
->profile_manager()->CreateProfileAsync(
277 ProfileManager::GetGuestProfilePath(),
278 base::Bind(&OnUserManagerGuestProfileCreated
,
279 profile_path_to_focus
,
287 void ShowUserManagerMaybeWithTutorial(Profile
* profile
) {
288 // Guest users cannot appear in the User Manager, nor display a tutorial.
289 if (!profile
|| profile
->IsGuestSession()) {
290 chrome::ShowUserManager(base::FilePath());
293 // Show the tutorial if the profile has not shown it before.
294 PrefService
* pref_service
= profile
->GetPrefs();
295 bool tutorial_shown
= pref_service
->GetBoolean(
296 prefs::kProfileUserManagerTutorialShown
);
298 pref_service
->SetBoolean(prefs::kProfileUserManagerTutorialShown
, true);
300 if (tutorial_shown
) {
301 chrome::ShowUserManager(profile
->GetPath());
303 chrome::ShowUserManagerWithTutorial(
304 profiles::USER_MANAGER_TUTORIAL_OVERVIEW
);
308 void EnableNewProfileManagementPreview() {
309 about_flags::PrefServiceFlagsStorage
flags_storage(
310 g_browser_process
->local_state());
311 about_flags::SetExperimentEnabled(
313 kNewProfileManagementExperimentInternalName
,
316 CommandLine::ForCurrentProcess()->AppendSwitch(
317 switches::kNewProfileManagement
);
318 chrome::ShowUserManagerWithTutorial(profiles::USER_MANAGER_TUTORIAL_OVERVIEW
);
321 void DisableNewProfileManagementPreview() {
322 about_flags::PrefServiceFlagsStorage
flags_storage(
323 g_browser_process
->local_state());
324 about_flags::SetExperimentEnabled(
326 kNewProfileManagementExperimentInternalName
,
328 chrome::AttemptRestart();
331 } // namespace profiles