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/common/chrome_switches.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/common/url_constants.h"
26 #include "components/signin/core/browser/account_reconcilor.h"
27 #include "components/signin/core/common/profile_management_switches.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/user_metrics.h"
32 #include "chrome/browser/ui/browser_finder.h"
33 #include "chrome/browser/ui/browser_list.h"
34 #include "chrome/browser/ui/browser_list_observer.h"
35 #include "chrome/browser/ui/browser_window.h"
36 #include "chrome/browser/ui/startup/startup_browser_creator.h"
37 #endif // !defined (OS_IOS)
39 using base::UserMetricsAction;
40 using content::BrowserThread;
44 const char kNewProfileManagementExperimentInternalName[] =
45 "enable-new-profile-management";
47 // Handles running a callback when a new Browser for the given profile
48 // has been completely created.
49 class BrowserAddedForProfileObserver : public chrome::BrowserListObserver {
51 BrowserAddedForProfileObserver(
53 profiles::ProfileSwitchingDoneCallback callback)
56 DCHECK(!callback_.is_null());
57 BrowserList::AddObserver(this);
59 virtual ~BrowserAddedForProfileObserver() {
63 // Overridden from BrowserListObserver:
64 virtual void OnBrowserAdded(Browser* browser) OVERRIDE {
65 if (browser->profile() == profile_) {
66 BrowserList::RemoveObserver(this);
68 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
72 // Profile for which the browser should be opened.
74 profiles::ProfileSwitchingDoneCallback callback_;
76 DISALLOW_COPY_AND_ASSIGN(BrowserAddedForProfileObserver);
79 void OpenBrowserWindowForProfile(
80 profiles::ProfileSwitchingDoneCallback 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())
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.
141 void OnUserManagerGuestProfileCreated(
142 const base::FilePath& profile_path_to_focus,
143 profiles::UserManagerTutorialMode tutorial_mode,
144 const base::Callback<void(Profile*, const std::string&)>& callback,
145 Profile* guest_profile,
146 Profile::CreateStatus status) {
147 if (status != Profile::CREATE_STATUS_INITIALIZED || callback.is_null())
150 // Tell the webui which user should be focused.
151 std::string page = chrome::kChromeUIUserManagerURL;
153 if (tutorial_mode == profiles::USER_MANAGER_TUTORIAL_OVERVIEW) {
155 } else if (!profile_path_to_focus.empty()) {
156 const ProfileInfoCache& cache =
157 g_browser_process->profile_manager()->GetProfileInfoCache();
158 size_t index = cache.GetIndexOfProfileWithPath(profile_path_to_focus);
159 if (index != std::string::npos) {
161 page += base::IntToString(index);
165 callback.Run(guest_profile, page);
168 // Updates Chrome services that require notification when
169 // the new_profile_management's status changes.
170 void UpdateServicesWithNewProfileManagementFlag(Profile* profile,
171 bool new_flag_status) {
172 AccountReconcilor* account_reconcilor =
173 AccountReconcilorFactory::GetForProfile(profile);
174 account_reconcilor->OnNewProfileManagementFlagChanged(new_flag_status);
181 void FindOrCreateNewWindowForProfile(
183 chrome::startup::IsProcessStartup process_startup,
184 chrome::startup::IsFirstRun is_first_run,
185 chrome::HostDesktopType desktop_type,
186 bool always_create) {
192 if (!always_create) {
193 Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
195 browser->window()->Activate();
200 content::RecordAction(UserMetricsAction("NewWindow"));
201 CommandLine command_line(CommandLine::NO_PROGRAM);
203 StartupBrowserCreator browser_creator;
204 browser_creator.LaunchBrowser(command_line, profile, base::FilePath(),
205 process_startup, is_first_run, &return_code);
206 #endif // defined(OS_IOS)
209 void SwitchToProfile(const base::FilePath& path,
210 chrome::HostDesktopType desktop_type,
212 ProfileSwitchingDoneCallback callback,
213 ProfileMetrics::ProfileOpen metric) {
214 g_browser_process->profile_manager()->CreateProfileAsync(
216 base::Bind(&OpenBrowserWindowForProfile,
224 ProfileMetrics::LogProfileSwitchUser(metric);
227 void SwitchToGuestProfile(chrome::HostDesktopType desktop_type,
228 ProfileSwitchingDoneCallback callback) {
229 g_browser_process->profile_manager()->CreateProfileAsync(
230 ProfileManager::GetGuestProfilePath(),
231 base::Bind(&OpenBrowserWindowForProfile,
239 ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_GUEST);
242 void CreateAndSwitchToNewProfile(chrome::HostDesktopType desktop_type,
243 ProfileSwitchingDoneCallback callback,
244 ProfileMetrics::ProfileAdd metric) {
245 ProfileInfoCache& cache =
246 g_browser_process->profile_manager()->GetProfileInfoCache();
248 int placeholder_avatar_index = profiles::GetPlaceholderAvatarIndex();
249 ProfileManager::CreateMultiProfileAsync(
250 cache.ChooseNameForNewProfile(placeholder_avatar_index),
251 base::UTF8ToUTF16(profiles::GetDefaultAvatarIconUrl(
252 placeholder_avatar_index)),
253 base::Bind(&OpenBrowserWindowForProfile,
259 ProfileMetrics::LogProfileAddNewUser(metric);
262 void CloseGuestProfileWindows() {
263 ProfileManager* profile_manager = g_browser_process->profile_manager();
264 Profile* profile = profile_manager->GetProfileByPath(
265 ProfileManager::GetGuestProfilePath());
268 BrowserList::CloseAllBrowsersWithProfile(profile);
272 void LockProfile(Profile* profile) {
274 ProfileInfoCache& cache =
275 g_browser_process->profile_manager()->GetProfileInfoCache();
277 size_t index = cache.GetIndexOfProfileWithPath(profile->GetPath());
278 cache.SetProfileSigninRequiredAtIndex(index, true);
279 chrome::ShowUserManager(profile->GetPath());
280 BrowserList::CloseAllBrowsersWithProfile(profile);
283 void CreateGuestProfileForUserManager(
284 const base::FilePath& profile_path_to_focus,
285 profiles::UserManagerTutorialMode tutorial_mode,
286 const base::Callback<void(Profile*, const std::string&)>& callback) {
287 // Create the guest profile, if necessary, and open the User Manager
288 // from the guest profile.
289 g_browser_process->profile_manager()->CreateProfileAsync(
290 ProfileManager::GetGuestProfilePath(),
291 base::Bind(&OnUserManagerGuestProfileCreated,
292 profile_path_to_focus,
300 void ShowUserManagerMaybeWithTutorial(Profile* profile) {
301 // Guest users cannot appear in the User Manager, nor display a tutorial.
302 if (!profile || profile->IsGuestSession()) {
303 chrome::ShowUserManager(base::FilePath());
306 chrome::ShowUserManagerWithTutorial(profiles::USER_MANAGER_TUTORIAL_OVERVIEW);
309 void EnableNewProfileManagementPreview(Profile* profile) {
310 #if defined(OS_ANDROID)
313 // TODO(rogerta): instead of setting experiment flags and command line
314 // args, we should set a profile preference.
315 const about_flags::Experiment experiment = {
316 kNewProfileManagementExperimentInternalName,
317 0, // string id for title of experiment
318 0, // string id for description of experiment
319 0, // supported platforms
320 about_flags::Experiment::ENABLE_DISABLE_VALUE,
321 switches::kEnableNewProfileManagement,
322 "", // not used with ENABLE_DISABLE_VALUE type
323 switches::kDisableNewProfileManagement,
324 "", // not used with ENABLE_DISABLE_VALUE type
325 NULL, // not used with ENABLE_DISABLE_VALUE type
328 about_flags::PrefServiceFlagsStorage flags_storage(
329 g_browser_process->local_state());
330 about_flags::SetExperimentEnabled(
332 experiment.NameForChoice(1),
335 switches::EnableNewProfileManagementForTesting(
336 CommandLine::ForCurrentProcess());
337 chrome::ShowUserManagerWithTutorial(profiles::USER_MANAGER_TUTORIAL_OVERVIEW);
338 UpdateServicesWithNewProfileManagementFlag(profile, true);
342 void DisableNewProfileManagementPreview(Profile* profile) {
343 about_flags::PrefServiceFlagsStorage flags_storage(
344 g_browser_process->local_state());
345 about_flags::SetExperimentEnabled(
347 kNewProfileManagementExperimentInternalName,
349 chrome::AttemptRestart();
350 UpdateServicesWithNewProfileManagementFlag(profile, false);
353 void BubbleViewModeFromAvatarBubbleMode(
354 BrowserWindow::AvatarBubbleMode mode,
355 BubbleViewMode* bubble_view_mode,
356 TutorialMode* tutorial_mode) {
357 *tutorial_mode = TUTORIAL_MODE_NONE;
359 case BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT:
360 *bubble_view_mode = BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
362 case BrowserWindow::AVATAR_BUBBLE_MODE_SIGNIN:
363 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_SIGNIN;
365 case BrowserWindow::AVATAR_BUBBLE_MODE_ADD_ACCOUNT:
366 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT;
368 case BrowserWindow::AVATAR_BUBBLE_MODE_REAUTH:
369 *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_REAUTH;
371 case BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN:
372 *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
373 *tutorial_mode = TUTORIAL_MODE_CONFIRM_SIGNIN;
375 case BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR:
376 *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
377 *tutorial_mode = TUTORIAL_MODE_SHOW_ERROR;
380 *bubble_view_mode = profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
384 } // namespace profiles