• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/profiles/profile_window.h"
6 
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/common/chrome_switches.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/common/url_constants.h"
25 #include "components/signin/core/browser/account_reconcilor.h"
26 #include "components/signin/core/common/profile_management_switches.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/user_metrics.h"
29 
30 #if !defined(OS_IOS)
31 #include "chrome/browser/ui/browser_finder.h"
32 #include "chrome/browser/ui/browser_list.h"
33 #include "chrome/browser/ui/browser_list_observer.h"
34 #include "chrome/browser/ui/browser_window.h"
35 #include "chrome/browser/ui/startup/startup_browser_creator.h"
36 #endif  // !defined (OS_IOS)
37 
38 using base::UserMetricsAction;
39 using content::BrowserThread;
40 
41 namespace {
42 
43 const char kNewProfileManagementExperimentInternalName[] =
44     "enable-new-profile-management";
45 
46 // Handles running a callback when a new Browser for the given profile
47 // has been completely created.
48 class BrowserAddedForProfileObserver : public chrome::BrowserListObserver {
49  public:
BrowserAddedForProfileObserver(Profile * profile,profiles::ProfileSwitchingDoneCallback callback)50   BrowserAddedForProfileObserver(
51       Profile* profile,
52       profiles::ProfileSwitchingDoneCallback callback)
53       : profile_(profile),
54         callback_(callback) {
55     DCHECK(!callback_.is_null());
56     BrowserList::AddObserver(this);
57   }
~BrowserAddedForProfileObserver()58   virtual ~BrowserAddedForProfileObserver() {
59   }
60 
61  private:
62   // Overridden from BrowserListObserver:
OnBrowserAdded(Browser * browser)63   virtual void OnBrowserAdded(Browser* browser) OVERRIDE {
64     if (browser->profile() == profile_) {
65       BrowserList::RemoveObserver(this);
66       callback_.Run();
67       base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
68     }
69   }
70 
71   // Profile for which the browser should be opened.
72   Profile* profile_;
73   profiles::ProfileSwitchingDoneCallback callback_;
74 
75   DISALLOW_COPY_AND_ASSIGN(BrowserAddedForProfileObserver);
76 };
77 
OpenBrowserWindowForProfile(profiles::ProfileSwitchingDoneCallback callback,bool always_create,bool is_new_profile,chrome::HostDesktopType desktop_type,Profile * profile,Profile::CreateStatus status)78 void OpenBrowserWindowForProfile(
79     profiles::ProfileSwitchingDoneCallback callback,
80     bool always_create,
81     bool is_new_profile,
82     chrome::HostDesktopType desktop_type,
83     Profile* profile,
84     Profile::CreateStatus status) {
85   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
86 
87   if (status != Profile::CREATE_STATUS_INITIALIZED)
88     return;
89 
90   chrome::startup::IsProcessStartup is_process_startup =
91       chrome::startup::IS_NOT_PROCESS_STARTUP;
92   chrome::startup::IsFirstRun is_first_run = chrome::startup::IS_NOT_FIRST_RUN;
93 
94   // If this is a brand new profile, then start a first run window.
95   if (is_new_profile) {
96     is_process_startup = chrome::startup::IS_PROCESS_STARTUP;
97     is_first_run = chrome::startup::IS_FIRST_RUN;
98   }
99 
100   // If |always_create| is false, and we have a |callback| to run, check
101   // whether a browser already exists so that we can run the callback. We don't
102   // want to rely on the observer listening to OnBrowserSetLastActive in this
103   // case, as you could manually activate an incorrect browser and trigger
104   // a false positive.
105   if (!always_create) {
106     Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
107     if (browser) {
108       browser->window()->Activate();
109       if (!callback.is_null())
110         callback.Run();
111       return;
112     }
113   }
114 
115   // If there is a callback, create an observer to make sure it is only
116   // run when the browser has been completely created. This observer will
117   // delete itself once that happens. This should not leak, because we are
118   // passing |always_create| = true to FindOrCreateNewWindow below, which ends
119   // up calling LaunchBrowser and opens a new window. If for whatever reason
120   // that fails, either something has crashed, or the observer will be cleaned
121   // up when a different browser for this profile is opened.
122   if (!callback.is_null())
123     new BrowserAddedForProfileObserver(profile, callback);
124 
125   // We already dealt with the case when |always_create| was false and a browser
126   // existed, which means that here a browser definitely needs to be created.
127   // Passing true for |always_create| means we won't duplicate the code that
128   // tries to find a browser.
129   profiles::FindOrCreateNewWindowForProfile(
130       profile,
131       is_process_startup,
132       is_first_run,
133       desktop_type,
134       true);
135 }
136 
137 // Called after a |guest_profile| is available to be used by the user manager.
138 // Based on the value of |tutorial_mode| we determine a url to be displayed
139 // by the webui and run the |callback|, if it exists.
OnUserManagerGuestProfileCreated(const base::FilePath & profile_path_to_focus,profiles::UserManagerTutorialMode tutorial_mode,const base::Callback<void (Profile *,const std::string &)> & callback,Profile * guest_profile,Profile::CreateStatus status)140 void OnUserManagerGuestProfileCreated(
141     const base::FilePath& profile_path_to_focus,
142     profiles::UserManagerTutorialMode tutorial_mode,
143     const base::Callback<void(Profile*, const std::string&)>& callback,
144     Profile* guest_profile,
145     Profile::CreateStatus status) {
146   if (status != Profile::CREATE_STATUS_INITIALIZED || callback.is_null())
147     return;
148 
149   // Tell the webui which user should be focused.
150   std::string page = chrome::kChromeUIUserManagerURL;
151 
152   if (tutorial_mode == profiles::USER_MANAGER_TUTORIAL_OVERVIEW) {
153     page += "#tutorial";
154   } else if (!profile_path_to_focus.empty()) {
155     const ProfileInfoCache& cache =
156         g_browser_process->profile_manager()->GetProfileInfoCache();
157     size_t index = cache.GetIndexOfProfileWithPath(profile_path_to_focus);
158     if (index != std::string::npos) {
159       page += "#";
160       page += base::IntToString(index);
161     }
162   }
163 
164   callback.Run(guest_profile, page);
165 }
166 
167 // Updates Chrome services that require notification when
168 // the new_profile_management's status changes.
UpdateServicesWithNewProfileManagementFlag(Profile * profile,bool new_flag_status)169 void UpdateServicesWithNewProfileManagementFlag(Profile* profile,
170                                                 bool new_flag_status) {
171   AccountReconcilor* account_reconcilor =
172       AccountReconcilorFactory::GetForProfile(profile);
173   account_reconcilor->OnNewProfileManagementFlagChanged(new_flag_status);
174 }
175 
176 }  // namespace
177 
178 namespace profiles {
179 
FindOrCreateNewWindowForProfile(Profile * profile,chrome::startup::IsProcessStartup process_startup,chrome::startup::IsFirstRun is_first_run,chrome::HostDesktopType desktop_type,bool always_create)180 void FindOrCreateNewWindowForProfile(
181     Profile* profile,
182     chrome::startup::IsProcessStartup process_startup,
183     chrome::startup::IsFirstRun is_first_run,
184     chrome::HostDesktopType desktop_type,
185     bool always_create) {
186 #if defined(OS_IOS)
187   NOTREACHED();
188 #else
189   DCHECK(profile);
190 
191   if (!always_create) {
192     Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
193     if (browser) {
194       browser->window()->Activate();
195       return;
196     }
197   }
198 
199   content::RecordAction(UserMetricsAction("NewWindow"));
200   CommandLine command_line(CommandLine::NO_PROGRAM);
201   int return_code;
202   StartupBrowserCreator browser_creator;
203   browser_creator.LaunchBrowser(command_line, profile, base::FilePath(),
204                                 process_startup, is_first_run, &return_code);
205 #endif  // defined(OS_IOS)
206 }
207 
SwitchToProfile(const base::FilePath & path,chrome::HostDesktopType desktop_type,bool always_create,ProfileSwitchingDoneCallback callback,ProfileMetrics::ProfileOpen metric)208 void SwitchToProfile(const base::FilePath& path,
209                      chrome::HostDesktopType desktop_type,
210                      bool always_create,
211                      ProfileSwitchingDoneCallback callback,
212                      ProfileMetrics::ProfileOpen metric) {
213   g_browser_process->profile_manager()->CreateProfileAsync(
214       path,
215       base::Bind(&OpenBrowserWindowForProfile,
216                  callback,
217                  always_create,
218                  false,
219                  desktop_type),
220       base::string16(),
221       base::string16(),
222       std::string());
223   ProfileMetrics::LogProfileSwitchUser(metric);
224 }
225 
SwitchToGuestProfile(chrome::HostDesktopType desktop_type,ProfileSwitchingDoneCallback callback)226 void SwitchToGuestProfile(chrome::HostDesktopType desktop_type,
227                           ProfileSwitchingDoneCallback callback) {
228   g_browser_process->profile_manager()->CreateProfileAsync(
229       ProfileManager::GetGuestProfilePath(),
230       base::Bind(&OpenBrowserWindowForProfile,
231                  callback,
232                  false,
233                  false,
234                  desktop_type),
235       base::string16(),
236       base::string16(),
237       std::string());
238   ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_GUEST);
239 }
240 
CreateAndSwitchToNewProfile(chrome::HostDesktopType desktop_type,ProfileSwitchingDoneCallback callback,ProfileMetrics::ProfileAdd metric)241 void CreateAndSwitchToNewProfile(chrome::HostDesktopType desktop_type,
242                                  ProfileSwitchingDoneCallback callback,
243                                  ProfileMetrics::ProfileAdd metric) {
244   ProfileInfoCache& cache =
245       g_browser_process->profile_manager()->GetProfileInfoCache();
246 
247   int placeholder_avatar_index = profiles::GetPlaceholderAvatarIndex();
248   ProfileManager::CreateMultiProfileAsync(
249       cache.ChooseNameForNewProfile(placeholder_avatar_index),
250       base::UTF8ToUTF16(profiles::GetDefaultAvatarIconUrl(
251           placeholder_avatar_index)),
252       base::Bind(&OpenBrowserWindowForProfile,
253                  callback,
254                  true,
255                  true,
256                  desktop_type),
257       std::string());
258   ProfileMetrics::LogProfileAddNewUser(metric);
259 }
260 
CloseGuestProfileWindows()261 void CloseGuestProfileWindows() {
262   ProfileManager* profile_manager = g_browser_process->profile_manager();
263   Profile* profile = profile_manager->GetProfileByPath(
264       ProfileManager::GetGuestProfilePath());
265 
266   if (profile) {
267     BrowserList::CloseAllBrowsersWithProfile(profile);
268   }
269 }
270 
LockProfile(Profile * profile)271 void LockProfile(Profile* profile) {
272   DCHECK(profile);
273   ProfileInfoCache& cache =
274       g_browser_process->profile_manager()->GetProfileInfoCache();
275 
276   size_t index = cache.GetIndexOfProfileWithPath(profile->GetPath());
277   cache.SetProfileSigninRequiredAtIndex(index, true);
278   chrome::ShowUserManager(profile->GetPath());
279   BrowserList::CloseAllBrowsersWithProfile(profile);
280 }
281 
CreateGuestProfileForUserManager(const base::FilePath & profile_path_to_focus,profiles::UserManagerTutorialMode tutorial_mode,const base::Callback<void (Profile *,const std::string &)> & callback)282 void CreateGuestProfileForUserManager(
283     const base::FilePath& profile_path_to_focus,
284     profiles::UserManagerTutorialMode tutorial_mode,
285     const base::Callback<void(Profile*, const std::string&)>& callback) {
286   // Create the guest profile, if necessary, and open the User Manager
287   // from the guest profile.
288   g_browser_process->profile_manager()->CreateProfileAsync(
289       ProfileManager::GetGuestProfilePath(),
290       base::Bind(&OnUserManagerGuestProfileCreated,
291                  profile_path_to_focus,
292                  tutorial_mode,
293                  callback),
294       base::string16(),
295       base::string16(),
296       std::string());
297 }
298 
ShowUserManagerMaybeWithTutorial(Profile * profile)299 void ShowUserManagerMaybeWithTutorial(Profile* profile) {
300   // Guest users cannot appear in the User Manager, nor display a tutorial.
301   if (!profile || profile->IsGuestSession()) {
302     chrome::ShowUserManager(base::FilePath());
303     return;
304   }
305   // Show the tutorial if the profile has not shown it before.
306   PrefService* pref_service = profile->GetPrefs();
307   bool tutorial_shown = pref_service->GetBoolean(
308       prefs::kProfileUserManagerTutorialShown);
309   if (!tutorial_shown)
310     pref_service->SetBoolean(prefs::kProfileUserManagerTutorialShown, true);
311 
312   if (tutorial_shown) {
313     chrome::ShowUserManager(profile->GetPath());
314   } else {
315     chrome::ShowUserManagerWithTutorial(
316         profiles::USER_MANAGER_TUTORIAL_OVERVIEW);
317   }
318 }
319 
EnableNewProfileManagementPreview(Profile * profile)320 void EnableNewProfileManagementPreview(Profile* profile) {
321 #if defined(OS_ANDROID)
322   NOTREACHED();
323 #else
324   // TODO(rogerta): instead of setting experiment flags and command line
325   // args, we should set a profile preference.
326   const about_flags::Experiment experiment = {
327       kNewProfileManagementExperimentInternalName,
328       0,  // string id for title of experiment
329       0,  // string id for description of experiment
330       0,  // supported platforms
331       about_flags::Experiment::ENABLE_DISABLE_VALUE,
332       switches::kEnableNewProfileManagement,
333       "",  // not used with ENABLE_DISABLE_VALUE type
334       switches::kDisableNewProfileManagement,
335       "",  // not used with ENABLE_DISABLE_VALUE type
336       NULL,  // not used with ENABLE_DISABLE_VALUE type
337       3
338   };
339   about_flags::PrefServiceFlagsStorage flags_storage(
340       g_browser_process->local_state());
341   about_flags::SetExperimentEnabled(
342       &flags_storage,
343       experiment.NameForChoice(1),
344       true);
345 
346   switches::EnableNewProfileManagementForTesting(
347       CommandLine::ForCurrentProcess());
348   chrome::ShowUserManagerWithTutorial(profiles::USER_MANAGER_TUTORIAL_OVERVIEW);
349   UpdateServicesWithNewProfileManagementFlag(profile, true);
350 #endif
351 }
352 
DisableNewProfileManagementPreview(Profile * profile)353 void DisableNewProfileManagementPreview(Profile* profile) {
354   about_flags::PrefServiceFlagsStorage flags_storage(
355       g_browser_process->local_state());
356   about_flags::SetExperimentEnabled(
357       &flags_storage,
358       kNewProfileManagementExperimentInternalName,
359       false);
360   chrome::AttemptRestart();
361   UpdateServicesWithNewProfileManagementFlag(profile, false);
362 }
363 
364 }  // namespace profiles
365