Home | History | Annotate | Download | only in profiles
      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   virtual ~BrowserAddedForProfileObserver() {
     61   }
     62 
     63  private:
     64   // Overridden from BrowserListObserver:
     65   virtual void OnBrowserAdded(Browser* browser) OVERRIDE {
     66     if (browser->profile() == profile_) {
     67       BrowserList::RemoveObserver(this);
     68       callback_.Run(profile_, Profile::CREATE_STATUS_INITIALIZED);
     69       base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
     70     }
     71   }
     72 
     73   // Profile for which the browser should be opened.
     74   Profile* profile_;
     75   ProfileManager::CreateCallback callback_;
     76 
     77   DISALLOW_COPY_AND_ASSIGN(BrowserAddedForProfileObserver);
     78 };
     79 
     80 void OpenBrowserWindowForProfile(
     81     ProfileManager::CreateCallback callback,
     82     bool always_create,
     83     bool is_new_profile,
     84     chrome::HostDesktopType desktop_type,
     85     Profile* profile,
     86     Profile::CreateStatus status) {
     87   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     88 
     89   if (status != Profile::CREATE_STATUS_INITIALIZED)
     90     return;
     91 
     92   chrome::startup::IsProcessStartup is_process_startup =
     93       chrome::startup::IS_NOT_PROCESS_STARTUP;
     94   chrome::startup::IsFirstRun is_first_run = chrome::startup::IS_NOT_FIRST_RUN;
     95 
     96   // If this is a brand new profile, then start a first run window.
     97   if (is_new_profile) {
     98     is_process_startup = chrome::startup::IS_PROCESS_STARTUP;
     99     is_first_run = chrome::startup::IS_FIRST_RUN;
    100   }
    101 
    102   // If |always_create| is false, and we have a |callback| to run, check
    103   // whether a browser already exists so that we can run the callback. We don't
    104   // want to rely on the observer listening to OnBrowserSetLastActive in this
    105   // case, as you could manually activate an incorrect browser and trigger
    106   // a false positive.
    107   if (!always_create) {
    108     Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
    109     if (browser) {
    110       browser->window()->Activate();
    111       if (!callback.is_null())
    112         callback.Run(profile, Profile::CREATE_STATUS_INITIALIZED);
    113       return;
    114     }
    115   }
    116 
    117   // If there is a callback, create an observer to make sure it is only
    118   // run when the browser has been completely created. This observer will
    119   // delete itself once that happens. This should not leak, because we are
    120   // passing |always_create| = true to FindOrCreateNewWindow below, which ends
    121   // up calling LaunchBrowser and opens a new window. If for whatever reason
    122   // that fails, either something has crashed, or the observer will be cleaned
    123   // up when a different browser for this profile is opened.
    124   if (!callback.is_null())
    125     new BrowserAddedForProfileObserver(profile, callback);
    126 
    127   // We already dealt with the case when |always_create| was false and a browser
    128   // existed, which means that here a browser definitely needs to be created.
    129   // Passing true for |always_create| means we won't duplicate the code that
    130   // tries to find a browser.
    131   profiles::FindOrCreateNewWindowForProfile(
    132       profile,
    133       is_process_startup,
    134       is_first_run,
    135       desktop_type,
    136       true);
    137 }
    138 
    139 // Called after a |guest_profile| is available to be used by the user manager.
    140 // Based on the value of |tutorial_mode| we determine a url to be displayed
    141 // by the webui and run the |callback|, if it exists. After opening a profile,
    142 // perform |profile_open_action|.
    143 void OnUserManagerGuestProfileCreated(
    144     const base::FilePath& profile_path_to_focus,
    145     profiles::UserManagerTutorialMode tutorial_mode,
    146     profiles::UserManagerProfileSelected profile_open_action,
    147     const base::Callback<void(Profile*, const std::string&)>& callback,
    148     Profile* guest_profile,
    149     Profile::CreateStatus status) {
    150   if (status != Profile::CREATE_STATUS_INITIALIZED || callback.is_null())
    151     return;
    152 
    153   // Tell the webui which user should be focused.
    154   std::string page = chrome::kChromeUIUserManagerURL;
    155 
    156   if (tutorial_mode == profiles::USER_MANAGER_TUTORIAL_OVERVIEW) {
    157     page += profiles::kUserManagerDisplayTutorial;
    158   } else if (!profile_path_to_focus.empty()) {
    159     const ProfileInfoCache& cache =
    160         g_browser_process->profile_manager()->GetProfileInfoCache();
    161     size_t index = cache.GetIndexOfProfileWithPath(profile_path_to_focus);
    162     if (index != std::string::npos) {
    163       page += "#";
    164       page += base::IntToString(index);
    165     }
    166   } else if (profile_open_action ==
    167              profiles::USER_MANAGER_SELECT_PROFILE_TASK_MANAGER) {
    168     page += profiles::kUserManagerSelectProfileTaskManager;
    169   } else if (profile_open_action ==
    170              profiles::USER_MANAGER_SELECT_PROFILE_ABOUT_CHROME) {
    171     page += profiles::kUserManagerSelectProfileAboutChrome;
    172   }
    173   callback.Run(guest_profile, page);
    174 }
    175 
    176 // Updates Chrome services that require notification when
    177 // the new_profile_management's status changes.
    178 void UpdateServicesWithNewProfileManagementFlag(Profile* profile,
    179                                                 bool new_flag_status) {
    180   AccountReconcilor* account_reconcilor =
    181       AccountReconcilorFactory::GetForProfile(profile);
    182   account_reconcilor->OnNewProfileManagementFlagChanged(new_flag_status);
    183 }
    184 
    185 }  // namespace
    186 
    187 namespace profiles {
    188 
    189 // User Manager parameters are prefixed with hash.
    190 const char kUserManagerDisplayTutorial[] = "#tutorial";
    191 const char kUserManagerSelectProfileTaskManager[] = "#task-manager";
    192 const char kUserManagerSelectProfileAboutChrome[] = "#about-chrome";
    193 
    194 void FindOrCreateNewWindowForProfile(
    195     Profile* profile,
    196     chrome::startup::IsProcessStartup process_startup,
    197     chrome::startup::IsFirstRun is_first_run,
    198     chrome::HostDesktopType desktop_type,
    199     bool always_create) {
    200 #if defined(OS_IOS)
    201   NOTREACHED();
    202 #else
    203   DCHECK(profile);
    204 
    205   if (!always_create) {
    206     Browser* browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
    207     if (browser) {
    208       browser->window()->Activate();
    209       return;
    210     }
    211   }
    212 
    213   content::RecordAction(UserMetricsAction("NewWindow"));
    214   CommandLine command_line(CommandLine::NO_PROGRAM);
    215   int return_code;
    216   StartupBrowserCreator browser_creator;
    217   browser_creator.LaunchBrowser(command_line, profile, base::FilePath(),
    218                                 process_startup, is_first_run, &return_code);
    219 #endif  // defined(OS_IOS)
    220 }
    221 
    222 void SwitchToProfile(const base::FilePath& path,
    223                      chrome::HostDesktopType desktop_type,
    224                      bool always_create,
    225                      ProfileManager::CreateCallback callback,
    226                      ProfileMetrics::ProfileOpen metric) {
    227   g_browser_process->profile_manager()->CreateProfileAsync(
    228       path,
    229       base::Bind(&OpenBrowserWindowForProfile,
    230                  callback,
    231                  always_create,
    232                  false,
    233                  desktop_type),
    234       base::string16(),
    235       base::string16(),
    236       std::string());
    237   ProfileMetrics::LogProfileSwitchUser(metric);
    238 }
    239 
    240 void SwitchToGuestProfile(chrome::HostDesktopType desktop_type,
    241                           ProfileManager::CreateCallback callback) {
    242   g_browser_process->profile_manager()->CreateProfileAsync(
    243       ProfileManager::GetGuestProfilePath(),
    244       base::Bind(&OpenBrowserWindowForProfile,
    245                  callback,
    246                  false,
    247                  false,
    248                  desktop_type),
    249       base::string16(),
    250       base::string16(),
    251       std::string());
    252   ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_GUEST);
    253 }
    254 
    255 void CreateAndSwitchToNewProfile(chrome::HostDesktopType desktop_type,
    256                                  ProfileManager::CreateCallback callback,
    257                                  ProfileMetrics::ProfileAdd metric) {
    258   ProfileInfoCache& cache =
    259       g_browser_process->profile_manager()->GetProfileInfoCache();
    260 
    261   int placeholder_avatar_index = profiles::GetPlaceholderAvatarIndex();
    262   ProfileManager::CreateMultiProfileAsync(
    263       cache.ChooseNameForNewProfile(placeholder_avatar_index),
    264       base::UTF8ToUTF16(profiles::GetDefaultAvatarIconUrl(
    265           placeholder_avatar_index)),
    266       base::Bind(&OpenBrowserWindowForProfile,
    267                  callback,
    268                  true,
    269                  true,
    270                  desktop_type),
    271       std::string());
    272   ProfileMetrics::LogProfileAddNewUser(metric);
    273 }
    274 
    275 void GuestBrowserCloseSuccess(const base::FilePath& profile_path) {
    276   UserManager::Show(profile_path,
    277                     profiles::USER_MANAGER_NO_TUTORIAL,
    278                     profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
    279 }
    280 
    281 void CloseGuestProfileWindows() {
    282   ProfileManager* profile_manager = g_browser_process->profile_manager();
    283   Profile* profile = profile_manager->GetProfileByPath(
    284       ProfileManager::GetGuestProfilePath());
    285 
    286   if (profile) {
    287     BrowserList::CloseAllBrowsersWithProfile(
    288         profile, base::Bind(&GuestBrowserCloseSuccess));
    289   }
    290 }
    291 
    292 void LockBrowserCloseSuccess(const base::FilePath& profile_path) {
    293   ProfileInfoCache* cache =
    294       &g_browser_process->profile_manager()->GetProfileInfoCache();
    295 
    296   cache->SetProfileSigninRequiredAtIndex(
    297       cache->GetIndexOfProfileWithPath(profile_path), true);
    298   UserManager::Show(profile_path,
    299                     profiles::USER_MANAGER_NO_TUTORIAL,
    300                     profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
    301 }
    302 
    303 void LockProfile(Profile* profile) {
    304   DCHECK(profile);
    305   if (profile) {
    306     BrowserList::CloseAllBrowsersWithProfile(
    307         profile, base::Bind(&LockBrowserCloseSuccess));
    308   }
    309 }
    310 
    311 void CreateGuestProfileForUserManager(
    312     const base::FilePath& profile_path_to_focus,
    313     profiles::UserManagerTutorialMode tutorial_mode,
    314     profiles::UserManagerProfileSelected profile_open_action,
    315     const base::Callback<void(Profile*, const std::string&)>& callback) {
    316   // Create the guest profile, if necessary, and open the User Manager
    317   // from the guest profile.
    318   g_browser_process->profile_manager()->CreateProfileAsync(
    319       ProfileManager::GetGuestProfilePath(),
    320       base::Bind(&OnUserManagerGuestProfileCreated,
    321                  profile_path_to_focus,
    322                  tutorial_mode,
    323                  profile_open_action,
    324                  callback),
    325       base::string16(),
    326       base::string16(),
    327       std::string());
    328 }
    329 
    330 void ShowUserManagerMaybeWithTutorial(Profile* profile) {
    331   // Guest users cannot appear in the User Manager, nor display a tutorial.
    332   if (!profile || profile->IsGuestSession()) {
    333     UserManager::Show(base::FilePath(),
    334                       profiles::USER_MANAGER_NO_TUTORIAL,
    335                       profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
    336     return;
    337   }
    338   UserManager::Show(base::FilePath(),
    339                     profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
    340                     profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
    341 }
    342 
    343 void EnableNewProfileManagementPreview(Profile* profile) {
    344 #if defined(OS_ANDROID)
    345   NOTREACHED();
    346 #else
    347   // TODO(rogerta): instead of setting experiment flags and command line
    348   // args, we should set a profile preference.
    349   const about_flags::Experiment experiment = {
    350       kNewProfileManagementExperimentInternalName,
    351       0,  // string id for title of experiment
    352       0,  // string id for description of experiment
    353       0,  // supported platforms
    354       about_flags::Experiment::ENABLE_DISABLE_VALUE,
    355       switches::kEnableNewProfileManagement,
    356       "",  // not used with ENABLE_DISABLE_VALUE type
    357       switches::kDisableNewProfileManagement,
    358       "",  // not used with ENABLE_DISABLE_VALUE type
    359       NULL,  // not used with ENABLE_DISABLE_VALUE type
    360       3
    361   };
    362   about_flags::PrefServiceFlagsStorage flags_storage(
    363       g_browser_process->local_state());
    364   about_flags::SetExperimentEnabled(
    365       &flags_storage,
    366       experiment.NameForChoice(1),
    367       true);
    368 
    369   switches::EnableNewProfileManagementForTesting(
    370       CommandLine::ForCurrentProcess());
    371   UserManager::Show(base::FilePath(),
    372                     profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
    373                     profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
    374   UpdateServicesWithNewProfileManagementFlag(profile, true);
    375 #endif
    376 }
    377 
    378 void DisableNewProfileManagementPreview(Profile* profile) {
    379   about_flags::PrefServiceFlagsStorage flags_storage(
    380       g_browser_process->local_state());
    381   about_flags::SetExperimentEnabled(
    382       &flags_storage,
    383       kNewProfileManagementExperimentInternalName,
    384       false);
    385   chrome::AttemptRestart();
    386   UpdateServicesWithNewProfileManagementFlag(profile, false);
    387 }
    388 
    389 void BubbleViewModeFromAvatarBubbleMode(
    390     BrowserWindow::AvatarBubbleMode mode,
    391     BubbleViewMode* bubble_view_mode,
    392     TutorialMode* tutorial_mode) {
    393   *tutorial_mode = TUTORIAL_MODE_NONE;
    394   switch (mode) {
    395     case BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT:
    396       *bubble_view_mode = BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
    397       return;
    398     case BrowserWindow::AVATAR_BUBBLE_MODE_SIGNIN:
    399       *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_SIGNIN;
    400       return;
    401     case BrowserWindow::AVATAR_BUBBLE_MODE_ADD_ACCOUNT:
    402       *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT;
    403       return;
    404     case BrowserWindow::AVATAR_BUBBLE_MODE_REAUTH:
    405       *bubble_view_mode = BUBBLE_VIEW_MODE_GAIA_REAUTH;
    406       return;
    407     case BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN:
    408       *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
    409       *tutorial_mode = TUTORIAL_MODE_CONFIRM_SIGNIN;
    410       return;
    411     case BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR:
    412       *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
    413       *tutorial_mode = TUTORIAL_MODE_SHOW_ERROR;
    414       return;
    415     default:
    416       *bubble_view_mode = profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
    417   }
    418 }
    419 
    420 }  // namespace profiles
    421