Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / profiles / profile_window.cc
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/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"
31
32 #if !defined(OS_IOS)
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)
39
40 using base::UserMetricsAction;
41 using content::BrowserThread;
42
43 namespace {
44
45 const char kNewProfileManagementExperimentInternalName[] =
46     "enable-new-profile-management";
47
48 // Handles running a callback when a new Browser for the given profile
49 // has been completely created.
50 class BrowserAddedForProfileObserver : public chrome::BrowserListObserver {
51  public:
52   BrowserAddedForProfileObserver(
53       Profile* profile,
54       ProfileManager::CreateCallback callback)
55       : profile_(profile),
56         callback_(callback) {
57     DCHECK(!callback_.is_null());
58     BrowserList::AddObserver(this);
59   }
60   ~BrowserAddedForProfileObserver() override {}
61
62  private:
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);
69     }
70   }
71
72   // Profile for which the browser should be opened.
73   Profile* profile_;
74   ProfileManager::CreateCallback callback_;
75
76   DISALLOW_COPY_AND_ASSIGN(BrowserAddedForProfileObserver);
77 };
78
79 void OpenBrowserWindowForProfile(
80     ProfileManager::CreateCallback callback,
81     bool always_create,
82     bool is_new_profile,
83     chrome::HostDesktopType desktop_type,
84     Profile* profile,
85     Profile::CreateStatus status) {
86   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
87
88   if (status != Profile::CREATE_STATUS_INITIALIZED)
89     return;
90
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;
94
95   // If this is a brand new profile, then start a first run window.
96   if (is_new_profile) {
97     is_process_startup = chrome::startup::IS_PROCESS_STARTUP;
98     is_first_run = chrome::startup::IS_FIRST_RUN;
99   }
100
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
105   // a false positive.
106   if (!always_create) {
107     Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
108     if (browser) {
109       browser->window()->Activate();
110       if (!callback.is_null())
111         callback.Run(profile, Profile::CREATE_STATUS_INITIALIZED);
112       return;
113     }
114   }
115
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);
125
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(
131       profile,
132       is_process_startup,
133       is_first_run,
134       desktop_type,
135       true);
136 }
137
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())
150     return;
151
152   // Tell the webui which user should be focused.
153   std::string page = chrome::kChromeUIUserManagerURL;
154
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) {
162       page += "#";
163       page += base::IntToString(index);
164     }
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;
177   }
178   callback.Run(guest_profile, page);
179 }
180
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);
188 }
189
190 }  // namespace
191
192 namespace profiles {
193
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";
200
201 void FindOrCreateNewWindowForProfile(
202     Profile* profile,
203     chrome::startup::IsProcessStartup process_startup,
204     chrome::startup::IsFirstRun is_first_run,
205     chrome::HostDesktopType desktop_type,
206     bool always_create) {
207 #if defined(OS_IOS)
208   NOTREACHED();
209 #else
210   DCHECK(profile);
211
212   if (!always_create) {
213     Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
214     if (browser) {
215       browser->window()->Activate();
216       return;
217     }
218   }
219
220   content::RecordAction(UserMetricsAction("NewWindow"));
221   CommandLine command_line(CommandLine::NO_PROGRAM);
222   int return_code;
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)
227 }
228
229 void SwitchToProfile(const base::FilePath& path,
230                      chrome::HostDesktopType desktop_type,
231                      bool always_create,
232                      ProfileManager::CreateCallback callback,
233                      ProfileMetrics::ProfileOpen metric) {
234   g_browser_process->profile_manager()->CreateProfileAsync(
235       path,
236       base::Bind(&OpenBrowserWindowForProfile,
237                  callback,
238                  always_create,
239                  false,
240                  desktop_type),
241       base::string16(),
242       base::string16(),
243       std::string());
244   ProfileMetrics::LogProfileSwitchUser(metric);
245 }
246
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,
252                  callback,
253                  false,
254                  false,
255                  desktop_type),
256       base::string16(),
257       base::string16(),
258       std::string());
259   ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_GUEST);
260 }
261
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();
267
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,
274                  callback,
275                  true,
276                  true,
277                  desktop_type),
278       std::string());
279   ProfileMetrics::LogProfileAddNewUser(metric);
280 }
281
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);
286 }
287
288 void CloseGuestProfileWindows() {
289   ProfileManager* profile_manager = g_browser_process->profile_manager();
290   Profile* profile = profile_manager->GetProfileByPath(
291       ProfileManager::GetGuestProfilePath());
292
293   if (profile) {
294     BrowserList::CloseAllBrowsersWithProfile(
295         profile, base::Bind(&GuestBrowserCloseSuccess));
296   }
297 }
298
299 void LockBrowserCloseSuccess(const base::FilePath& profile_path) {
300   ProfileInfoCache* cache =
301       &g_browser_process->profile_manager()->GetProfileInfoCache();
302
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);
309 }
310
311 void LockProfile(Profile* profile) {
312   DCHECK(profile);
313   if (profile) {
314     BrowserList::CloseAllBrowsersWithProfile(
315         profile, base::Bind(&LockBrowserCloseSuccess));
316   }
317 }
318
319 bool IsLockAvailable(Profile* profile) {
320   DCHECK(profile);
321   if (!switches::IsNewProfileManagement())
322     return false;
323
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") {
330     return false;
331   }
332
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))
337       return true;
338   }
339   return false;
340 }
341
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,
353                  tutorial_mode,
354                  profile_open_action,
355                  callback),
356       base::string16(),
357       base::string16(),
358       std::string());
359 }
360
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);
367     return;
368   }
369   UserManager::Show(base::FilePath(),
370                     profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
371                     profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
372 }
373
374 void EnableNewProfileManagementPreview(Profile* profile) {
375 #if defined(OS_ANDROID)
376   NOTREACHED();
377 #else
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
391       3
392   };
393   about_flags::PrefServiceFlagsStorage flags_storage(
394       g_browser_process->local_state());
395   about_flags::SetExperimentEnabled(
396       &flags_storage,
397       experiment.NameForChoice(1),
398       true);
399
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);
406 #endif
407 }
408
409 void DisableNewProfileManagementPreview(Profile* profile) {
410   about_flags::PrefServiceFlagsStorage flags_storage(
411       g_browser_process->local_state());
412   about_flags::SetExperimentEnabled(
413       &flags_storage,
414       kNewProfileManagementExperimentInternalName,
415       false);
416   chrome::AttemptRestart();
417   UpdateServicesWithNewProfileManagementFlag(profile, false);
418 }
419
420 void BubbleViewModeFromAvatarBubbleMode(
421     BrowserWindow::AvatarBubbleMode mode,
422     BubbleViewMode* bubble_view_mode,
423     TutorialMode* tutorial_mode) {
424   *tutorial_mode = TUTORIAL_MODE_NONE;
425   switch (mode) {
426     case BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT:
427       *bubble_view_mode = BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
428       return;
429     case BrowserWindow::AVATAR_BUBBLE_MODE_SIGNIN:
430       *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_SIGNIN;
431       return;
432     case BrowserWindow::AVATAR_BUBBLE_MODE_ADD_ACCOUNT:
433       *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT;
434       return;
435     case BrowserWindow::AVATAR_BUBBLE_MODE_REAUTH:
436       *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_REAUTH;
437       return;
438     case BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN:
439       *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
440       *tutorial_mode = TUTORIAL_MODE_CONFIRM_SIGNIN;
441       return;
442     case BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR:
443       *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
444       *tutorial_mode = TUTORIAL_MODE_SHOW_ERROR;
445       return;
446     default:
447       *bubble_view_mode = profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
448   }
449 }
450
451 }  // namespace profiles