Home | History | Annotate | Download | only in options
      1 // Copyright (c) 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/ui/webui/options/manage_profile_handler.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/command_line.h"
     10 #include "base/prefs/pref_service.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/value_conversions.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/browser_process.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "chrome/browser/managed_mode/managed_user_service.h"
     18 #include "chrome/browser/prefs/scoped_user_pref_update.h"
     19 #include "chrome/browser/profiles/gaia_info_update_service.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/profiles/profile_info_cache.h"
     22 #include "chrome/browser/profiles/profile_info_util.h"
     23 #include "chrome/browser/profiles/profile_manager.h"
     24 #include "chrome/browser/profiles/profile_metrics.h"
     25 #include "chrome/browser/profiles/profile_shortcut_manager.h"
     26 #include "chrome/browser/profiles/profile_window.h"
     27 #include "chrome/browser/profiles/profiles_state.h"
     28 #include "chrome/browser/signin/signin_manager.h"
     29 #include "chrome/browser/signin/signin_manager_factory.h"
     30 #include "chrome/browser/sync/profile_sync_service.h"
     31 #include "chrome/browser/sync/profile_sync_service_factory.h"
     32 #include "chrome/browser/ui/browser_finder.h"
     33 #include "chrome/common/chrome_switches.h"
     34 #include "chrome/common/pref_names.h"
     35 #include "content/public/browser/browser_thread.h"
     36 #include "content/public/browser/notification_service.h"
     37 #include "content/public/browser/web_ui.h"
     38 #include "grit/generated_resources.h"
     39 #include "ui/base/l10n/l10n_util.h"
     40 #include "ui/webui/web_ui_util.h"
     41 
     42 #if defined(ENABLE_SETTINGS_APP)
     43 #include "chrome/browser/ui/app_list/app_list_service.h"
     44 #include "content/public/browser/web_contents.h"
     45 #endif
     46 
     47 namespace options {
     48 
     49 namespace {
     50 
     51 const char kCreateProfileIconGridName[] = "create-profile-icon-grid";
     52 const char kManageProfileIconGridName[] = "manage-profile-icon-grid";
     53 
     54 // Given |args| from the WebUI, parses value 0 as a FilePath |profile_file_path|
     55 // and returns true on success.
     56 bool GetProfilePathFromArgs(const ListValue* args,
     57                             base::FilePath* profile_file_path) {
     58   const Value* file_path_value;
     59   if (!args->Get(0, &file_path_value))
     60     return false;
     61   return base::GetValueAsFilePath(*file_path_value, profile_file_path);
     62 }
     63 
     64 void OnNewDefaultProfileCreated(
     65     chrome::HostDesktopType desktop_type,
     66     Profile* profile,
     67     Profile::CreateStatus status) {
     68   if (status == Profile::CREATE_STATUS_INITIALIZED) {
     69     profiles::FindOrCreateNewWindowForProfile(
     70         profile,
     71         chrome::startup::IS_PROCESS_STARTUP,
     72         chrome::startup::IS_FIRST_RUN,
     73         desktop_type,
     74         false);
     75   }
     76 }
     77 
     78 }  // namespace
     79 
     80 ManageProfileHandler::ManageProfileHandler()
     81     : weak_factory_(this) {
     82 }
     83 
     84 ManageProfileHandler::~ManageProfileHandler() {
     85   ProfileSyncService* service =
     86       ProfileSyncServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()));
     87   // Sync may be disabled in tests.
     88   if (service)
     89     service->RemoveObserver(this);
     90 }
     91 
     92 void ManageProfileHandler::GetLocalizedValues(
     93     DictionaryValue* localized_strings) {
     94   DCHECK(localized_strings);
     95 
     96   static OptionsStringResource resources[] = {
     97     { "manageProfilesNameLabel", IDS_PROFILES_MANAGE_NAME_LABEL },
     98     { "manageProfilesDuplicateNameError",
     99         IDS_PROFILES_MANAGE_DUPLICATE_NAME_ERROR },
    100     { "manageProfilesIconLabel", IDS_PROFILES_MANAGE_ICON_LABEL },
    101     { "manageProfilesManagedSignedInLabel",
    102         IDS_PROFILES_CREATE_MANAGED_SIGNED_IN_LABEL },
    103     { "manageProfilesManagedNotSignedInLabel",
    104         IDS_PROFILES_CREATE_MANAGED_NOT_SIGNED_IN_LABEL },
    105     { "manageProfilesManagedAccountDetailsOutOfDate",
    106         IDS_PROFILES_CREATE_MANAGED_ACCOUNT_DETAILS_OUT_OF_DATE_LABEL },
    107     { "manageProfilesManagedSignInAgainLink",
    108         IDS_PROFILES_CREATE_MANAGED_ACCOUNT_SIGN_IN_AGAIN_LINK },
    109     { "manageProfilesManagedNotSignedInLink",
    110         IDS_PROFILES_CREATE_MANAGED_NOT_SIGNED_IN_LINK },
    111     { "manageProfilesSelectExistingManagedProfileLabel",
    112         IDS_PROFILES_CREATE_MANAGED_FROM_EXISTING_LABEL},
    113     { "deleteProfileTitle", IDS_PROFILES_DELETE_TITLE },
    114     { "deleteProfileOK", IDS_PROFILES_DELETE_OK_BUTTON_LABEL },
    115     { "deleteProfileMessage", IDS_PROFILES_DELETE_MESSAGE },
    116     { "deleteManagedProfileAddendum", IDS_PROFILES_DELETE_MANAGED_ADDENDUM },
    117     { "createProfileTitle", IDS_PROFILES_CREATE_TITLE },
    118     { "createProfileInstructions", IDS_PROFILES_CREATE_INSTRUCTIONS },
    119     { "createProfileConfirm", IDS_PROFILES_CREATE_CONFIRM },
    120     { "createProfileLocalError", IDS_PROFILES_CREATE_LOCAL_ERROR },
    121     { "createProfileRemoteError", IDS_PROFILES_CREATE_REMOTE_ERROR },
    122     { "createProfileShortcutCheckbox", IDS_PROFILES_CREATE_SHORTCUT_CHECKBOX },
    123     { "createProfileShortcutButton", IDS_PROFILES_CREATE_SHORTCUT_BUTTON },
    124     { "removeProfileShortcutButton", IDS_PROFILES_REMOVE_SHORTCUT_BUTTON },
    125   };
    126 
    127   RegisterStrings(localized_strings, resources, arraysize(resources));
    128   RegisterTitle(localized_strings, "manageProfile",
    129                 IDS_PROFILES_MANAGE_TITLE);
    130   RegisterTitle(localized_strings, "createProfile",
    131                 IDS_PROFILES_CREATE_TITLE);
    132 
    133   localized_strings->SetBoolean("profileShortcutsEnabled",
    134                                 ProfileShortcutManager::IsFeatureEnabled());
    135   localized_strings->SetBoolean("managedUsersEnabled",
    136                                 ManagedUserService::AreManagedUsersEnabled());
    137 
    138   localized_strings->SetBoolean(
    139       "allowCreateExistingManagedUsers",
    140       CommandLine::ForCurrentProcess()->HasSwitch(
    141           switches::kAllowCreateExistingManagedUsers));
    142 }
    143 
    144 void ManageProfileHandler::InitializeHandler() {
    145   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
    146                  content::NotificationService::AllSources());
    147 
    148   Profile* profile = Profile::FromWebUI(web_ui());
    149   pref_change_registrar_.Init(profile->GetPrefs());
    150   pref_change_registrar_.Add(
    151       prefs::kManagedUserCreationAllowed,
    152       base::Bind(&ManageProfileHandler::OnCreateManagedUserPrefChange,
    153                  base::Unretained(this)));
    154   ProfileSyncService* service =
    155       ProfileSyncServiceFactory::GetForProfile(profile);
    156   // Sync may be disabled for tests.
    157   if (service)
    158     service->AddObserver(this);
    159 }
    160 
    161 void ManageProfileHandler::InitializePage() {
    162   SendProfileNames();
    163   OnCreateManagedUserPrefChange();
    164 }
    165 
    166 void ManageProfileHandler::RegisterMessages() {
    167   web_ui()->RegisterMessageCallback("setProfileIconAndName",
    168       base::Bind(&ManageProfileHandler::SetProfileIconAndName,
    169                  base::Unretained(this)));
    170   web_ui()->RegisterMessageCallback("requestDefaultProfileIcons",
    171       base::Bind(&ManageProfileHandler::RequestDefaultProfileIcons,
    172                  base::Unretained(this)));
    173   web_ui()->RegisterMessageCallback("requestNewProfileDefaults",
    174       base::Bind(&ManageProfileHandler::RequestNewProfileDefaults,
    175                  base::Unretained(this)));
    176   web_ui()->RegisterMessageCallback("requestHasProfileShortcuts",
    177       base::Bind(&ManageProfileHandler::RequestHasProfileShortcuts,
    178                  base::Unretained(this)));
    179   web_ui()->RegisterMessageCallback("requestCreateProfileUpdate",
    180       base::Bind(&ManageProfileHandler::RequestCreateProfileUpdate,
    181                  base::Unretained(this)));
    182   web_ui()->RegisterMessageCallback("profileIconSelectionChanged",
    183       base::Bind(&ManageProfileHandler::ProfileIconSelectionChanged,
    184                  base::Unretained(this)));
    185 #if defined(ENABLE_SETTINGS_APP)
    186   web_ui()->RegisterMessageCallback("switchAppListProfile",
    187       base::Bind(&ManageProfileHandler::SwitchAppListProfile,
    188                  base::Unretained(this)));
    189 #endif
    190   web_ui()->RegisterMessageCallback("addProfileShortcut",
    191       base::Bind(&ManageProfileHandler::AddProfileShortcut,
    192                  base::Unretained(this)));
    193   web_ui()->RegisterMessageCallback("removeProfileShortcut",
    194       base::Bind(&ManageProfileHandler::RemoveProfileShortcut,
    195                  base::Unretained(this)));
    196   web_ui()->RegisterMessageCallback("requestExistingManagedUsers",
    197       base::Bind(&ManageProfileHandler::RequestExistingManagedUsers,
    198                  base::Unretained(this)));
    199 }
    200 
    201 void ManageProfileHandler::Observe(
    202     int type,
    203     const content::NotificationSource& source,
    204     const content::NotificationDetails& details) {
    205   if (type == chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED) {
    206     // If the browser shuts down during supervised-profile creation, deleting
    207     // the unregistered supervised-user profile triggers this notification,
    208     // but the RenderViewHost the profile info would be sent to has already been
    209     // destroyed.
    210     if (!web_ui()->GetWebContents()->GetRenderViewHost())
    211       return;
    212     SendProfileNames();
    213     base::StringValue value(kManageProfileIconGridName);
    214     SendProfileIcons(value);
    215   } else {
    216     OptionsPageUIHandler::Observe(type, source, details);
    217   }
    218 }
    219 
    220 void ManageProfileHandler::OnStateChanged() {
    221   RequestCreateProfileUpdate(NULL);
    222 }
    223 
    224 void ManageProfileHandler::RequestDefaultProfileIcons(const ListValue* args) {
    225   base::StringValue create_value(kCreateProfileIconGridName);
    226   base::StringValue manage_value(kManageProfileIconGridName);
    227   SendProfileIcons(manage_value);
    228   SendProfileIcons(create_value);
    229 }
    230 
    231 void ManageProfileHandler::RequestNewProfileDefaults(const ListValue* args) {
    232   const ProfileInfoCache& cache =
    233       g_browser_process->profile_manager()->GetProfileInfoCache();
    234   const size_t icon_index = cache.ChooseAvatarIconIndexForNewProfile();
    235 
    236   DictionaryValue profile_info;
    237   profile_info.SetString("name", cache.ChooseNameForNewProfile(icon_index));
    238   profile_info.SetString("iconURL", cache.GetDefaultAvatarIconUrl(icon_index));
    239 
    240   web_ui()->CallJavascriptFunction(
    241       "ManageProfileOverlay.receiveNewProfileDefaults", profile_info);
    242 }
    243 
    244 void ManageProfileHandler::RequestExistingManagedUsers(const ListValue* args) {
    245   Profile* profile = Profile::FromWebUI(web_ui());
    246   if (profile->IsManaged())
    247     return;
    248 
    249   const ProfileInfoCache& cache =
    250       g_browser_process->profile_manager()->GetProfileInfoCache();
    251   std::set<std::string> managed_user_ids;
    252   for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i)
    253     managed_user_ids.insert(cache.GetManagedUserIdOfProfileAtIndex(i));
    254 
    255   const DictionaryValue* dict =
    256       profile->GetPrefs()->GetDictionary(prefs::kManagedUsers);
    257   DictionaryValue id_names_dict;
    258   for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
    259     if (managed_user_ids.find(it.key()) != managed_user_ids.end())
    260       continue;
    261     const DictionaryValue* value = NULL;
    262     bool success = it.value().GetAsDictionary(&value);
    263     DCHECK(success);
    264     std::string name;
    265     value->GetString("name", &name);
    266     id_names_dict.SetString(it.key(), name);
    267   }
    268 
    269   web_ui()->CallJavascriptFunction(
    270       "CreateProfileOverlay.receiveExistingManagedUsers", id_names_dict);
    271 }
    272 
    273 void ManageProfileHandler::SendProfileIcons(
    274     const base::StringValue& icon_grid) {
    275   ListValue image_url_list;
    276 
    277   // First add the GAIA picture if it's available.
    278   const ProfileInfoCache& cache =
    279       g_browser_process->profile_manager()->GetProfileInfoCache();
    280   Profile* profile = Profile::FromWebUI(web_ui());
    281   size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
    282   if (profile_index != std::string::npos) {
    283     const gfx::Image* icon =
    284         cache.GetGAIAPictureOfProfileAtIndex(profile_index);
    285     if (icon) {
    286       gfx::Image icon2 = profiles::GetAvatarIconForWebUI(*icon, true);
    287       gaia_picture_url_ = webui::GetBitmapDataUrl(icon2.AsBitmap());
    288       image_url_list.Append(new base::StringValue(gaia_picture_url_));
    289     }
    290   }
    291 
    292   // Next add the default avatar icons.
    293   for (size_t i = 0; i < ProfileInfoCache::GetDefaultAvatarIconCount(); i++) {
    294     std::string url = ProfileInfoCache::GetDefaultAvatarIconUrl(i);
    295     image_url_list.Append(new base::StringValue(url));
    296   }
    297 
    298   web_ui()->CallJavascriptFunction(
    299       "ManageProfileOverlay.receiveDefaultProfileIcons", icon_grid,
    300       image_url_list);
    301 }
    302 
    303 void ManageProfileHandler::SendProfileNames() {
    304   const ProfileInfoCache& cache =
    305       g_browser_process->profile_manager()->GetProfileInfoCache();
    306   DictionaryValue profile_name_dict;
    307   for (size_t i = 0, e = cache.GetNumberOfProfiles(); i < e; ++i)
    308     profile_name_dict.SetBoolean(UTF16ToUTF8(cache.GetNameOfProfileAtIndex(i)),
    309                                  true);
    310 
    311   web_ui()->CallJavascriptFunction("ManageProfileOverlay.receiveProfileNames",
    312                                    profile_name_dict);
    313 }
    314 
    315 void ManageProfileHandler::SetProfileIconAndName(const ListValue* args) {
    316   DCHECK(args);
    317 
    318   base::FilePath profile_file_path;
    319   if (!GetProfilePathFromArgs(args, &profile_file_path))
    320     return;
    321 
    322   ProfileInfoCache& cache =
    323       g_browser_process->profile_manager()->GetProfileInfoCache();
    324   size_t profile_index = cache.GetIndexOfProfileWithPath(profile_file_path);
    325   if (profile_index == std::string::npos)
    326     return;
    327 
    328   Profile* profile =
    329       g_browser_process->profile_manager()->GetProfile(profile_file_path);
    330   if (!profile)
    331     return;
    332 
    333   std::string icon_url;
    334   if (!args->GetString(1, &icon_url))
    335     return;
    336 
    337   // Metrics logging variable.
    338   bool previously_using_gaia_icon =
    339       cache.IsUsingGAIAPictureOfProfileAtIndex(profile_index);
    340 
    341   size_t new_icon_index;
    342   if (icon_url == gaia_picture_url_) {
    343     cache.SetIsUsingGAIAPictureOfProfileAtIndex(profile_index, true);
    344     if (!previously_using_gaia_icon) {
    345       // Only log if they changed to the GAIA photo.
    346       // Selection of GAIA photo as avatar is logged as part of the function
    347       // below.
    348       ProfileMetrics::LogProfileSwitchGaia(ProfileMetrics::GAIA_OPT_IN);
    349     }
    350   } else if (cache.IsDefaultAvatarIconUrl(icon_url, &new_icon_index)) {
    351     ProfileMetrics::LogProfileAvatarSelection(new_icon_index);
    352     PrefService* pref_service = profile->GetPrefs();
    353     // Updating the profile preference will cause the cache to be updated for
    354     // this preference.
    355     pref_service->SetInteger(prefs::kProfileAvatarIndex, new_icon_index);
    356     cache.SetIsUsingGAIAPictureOfProfileAtIndex(profile_index, false);
    357   }
    358   ProfileMetrics::LogProfileUpdate(profile_file_path);
    359 
    360   if (profile->IsManaged())
    361     return;
    362 
    363   string16 new_profile_name;
    364   if (!args->GetString(2, &new_profile_name))
    365     return;
    366 
    367   if (new_profile_name == cache.GetGAIANameOfProfileAtIndex(profile_index)) {
    368     // Set the profile to use the GAIA name as the profile name. Note, this
    369     // is a little weird if the user typed their GAIA name manually but
    370     // it's not a big deal.
    371     cache.SetIsUsingGAIANameOfProfileAtIndex(profile_index, true);
    372   } else {
    373     PrefService* pref_service = profile->GetPrefs();
    374     // Updating the profile preference will cause the cache to be updated for
    375     // this preference.
    376     pref_service->SetString(prefs::kProfileName, UTF16ToUTF8(new_profile_name));
    377 
    378     // Changing the profile name can invalidate the profile index.
    379     profile_index = cache.GetIndexOfProfileWithPath(profile_file_path);
    380     if (profile_index == std::string::npos)
    381       return;
    382 
    383     cache.SetIsUsingGAIANameOfProfileAtIndex(profile_index, false);
    384   }
    385 }
    386 
    387 #if defined(ENABLE_SETTINGS_APP)
    388 void ManageProfileHandler::SwitchAppListProfile(const ListValue* args) {
    389   DCHECK(args);
    390   DCHECK(profiles::IsMultipleProfilesEnabled());
    391 
    392   const Value* file_path_value;
    393   base::FilePath profile_file_path;
    394   if (!args->Get(0, &file_path_value) ||
    395       !base::GetValueAsFilePath(*file_path_value, &profile_file_path))
    396     return;
    397 
    398   AppListService* app_list_service = AppListService::Get();
    399   app_list_service->SetProfilePath(profile_file_path);
    400   app_list_service->Show();
    401 
    402   // Close the settings app, since it will now be for the wrong profile.
    403   web_ui()->GetWebContents()->Close();
    404 }
    405 #endif  // defined(ENABLE_SETTINGS_APP)
    406 
    407 void ManageProfileHandler::ProfileIconSelectionChanged(
    408     const base::ListValue* args) {
    409   DCHECK(args);
    410 
    411   base::FilePath profile_file_path;
    412   if (!GetProfilePathFromArgs(args, &profile_file_path))
    413     return;
    414 
    415   // Currently this only supports editing the current profile's info.
    416   if (profile_file_path != Profile::FromWebUI(web_ui())->GetPath())
    417     return;
    418 
    419   std::string icon_url;
    420   if (!args->GetString(1, &icon_url))
    421     return;
    422 
    423   if (icon_url != gaia_picture_url_)
    424     return;
    425 
    426   // If the selection is the GAIA picture then also show the GAIA name in the
    427   // text field.
    428   ProfileInfoCache& cache =
    429       g_browser_process->profile_manager()->GetProfileInfoCache();
    430   size_t profile_index = cache.GetIndexOfProfileWithPath(profile_file_path);
    431   if (profile_index == std::string::npos)
    432     return;
    433   string16 gaia_name = cache.GetGAIANameOfProfileAtIndex(profile_index);
    434   if (gaia_name.empty())
    435     return;
    436 
    437   StringValue gaia_name_value(gaia_name);
    438   web_ui()->CallJavascriptFunction("ManageProfileOverlay.setProfileName",
    439                                    gaia_name_value);
    440 }
    441 
    442 void ManageProfileHandler::RequestHasProfileShortcuts(const ListValue* args) {
    443   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    444   DCHECK(ProfileShortcutManager::IsFeatureEnabled());
    445 
    446   base::FilePath profile_file_path;
    447   if (!GetProfilePathFromArgs(args, &profile_file_path))
    448     return;
    449 
    450   const ProfileInfoCache& cache =
    451       g_browser_process->profile_manager()->GetProfileInfoCache();
    452   size_t profile_index = cache.GetIndexOfProfileWithPath(profile_file_path);
    453   if (profile_index == std::string::npos)
    454     return;
    455 
    456   const base::FilePath profile_path =
    457       cache.GetPathOfProfileAtIndex(profile_index);
    458   ProfileShortcutManager* shortcut_manager =
    459       g_browser_process->profile_manager()->profile_shortcut_manager();
    460   shortcut_manager->HasProfileShortcuts(
    461       profile_path, base::Bind(&ManageProfileHandler::OnHasProfileShortcuts,
    462                                weak_factory_.GetWeakPtr()));
    463 }
    464 
    465 void ManageProfileHandler::RequestCreateProfileUpdate(
    466     const base::ListValue* args) {
    467   Profile* profile = Profile::FromWebUI(web_ui());
    468   SigninManagerBase* manager =
    469       SigninManagerFactory::GetForProfile(profile);
    470   string16 username = UTF8ToUTF16(manager->GetAuthenticatedUsername());
    471   ProfileSyncService* service =
    472      ProfileSyncServiceFactory::GetForProfile(profile);
    473   GoogleServiceAuthError::State state = service->GetAuthError().state();
    474   bool has_error = (state == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
    475                     state == GoogleServiceAuthError::USER_NOT_SIGNED_UP ||
    476                     state == GoogleServiceAuthError::ACCOUNT_DELETED ||
    477                     state == GoogleServiceAuthError::ACCOUNT_DISABLED);
    478   web_ui()->CallJavascriptFunction("CreateProfileOverlay.updateSignedInStatus",
    479                                    base::StringValue(username),
    480                                    base::FundamentalValue(has_error));
    481   OnCreateManagedUserPrefChange();
    482 }
    483 
    484 void ManageProfileHandler::OnCreateManagedUserPrefChange() {
    485   PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
    486   base::FundamentalValue allowed(
    487       prefs->GetBoolean(prefs::kManagedUserCreationAllowed));
    488   web_ui()->CallJavascriptFunction(
    489       "CreateProfileOverlay.updateManagedUsersAllowed", allowed);
    490 }
    491 
    492 void ManageProfileHandler::OnHasProfileShortcuts(bool has_shortcuts) {
    493   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    494 
    495   const base::FundamentalValue has_shortcuts_value(has_shortcuts);
    496   web_ui()->CallJavascriptFunction(
    497       "ManageProfileOverlay.receiveHasProfileShortcuts", has_shortcuts_value);
    498 }
    499 
    500 void ManageProfileHandler::AddProfileShortcut(const base::ListValue* args) {
    501   base::FilePath profile_file_path;
    502   if (!GetProfilePathFromArgs(args, &profile_file_path))
    503     return;
    504 
    505   DCHECK(ProfileShortcutManager::IsFeatureEnabled());
    506   ProfileShortcutManager* shortcut_manager =
    507       g_browser_process->profile_manager()->profile_shortcut_manager();
    508   DCHECK(shortcut_manager);
    509 
    510   shortcut_manager->CreateProfileShortcut(profile_file_path);
    511 
    512   // Update the UI buttons.
    513   OnHasProfileShortcuts(true);
    514 }
    515 
    516 void ManageProfileHandler::RemoveProfileShortcut(const base::ListValue* args) {
    517   base::FilePath profile_file_path;
    518   if (!GetProfilePathFromArgs(args, &profile_file_path))
    519     return;
    520 
    521   DCHECK(ProfileShortcutManager::IsFeatureEnabled());
    522   ProfileShortcutManager* shortcut_manager =
    523     g_browser_process->profile_manager()->profile_shortcut_manager();
    524   DCHECK(shortcut_manager);
    525 
    526   shortcut_manager->RemoveProfileShortcuts(profile_file_path);
    527 
    528   // Update the UI buttons.
    529   OnHasProfileShortcuts(false);
    530 }
    531 
    532 }  // namespace options
    533