content_settings_handler.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
1// Copyright (c) 2012 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/content_settings_handler.h" 6 7#include <algorithm> 8#include <map> 9#include <vector> 10 11#include "base/bind.h" 12#include "base/bind_helpers.h" 13#include "base/command_line.h" 14#include "base/prefs/pref_service.h" 15#include "base/strings/string_number_conversions.h" 16#include "base/strings/utf_string_conversions.h" 17#include "base/values.h" 18#include "chrome/browser/browser_process.h" 19#include "chrome/browser/chrome_notification_types.h" 20#include "chrome/browser/content_settings/content_settings_details.h" 21#include "chrome/browser/content_settings/content_settings_utils.h" 22#include "chrome/browser/content_settings/host_content_settings_map.h" 23#include "chrome/browser/custom_handlers/protocol_handler_registry.h" 24#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" 25#include "chrome/browser/extensions/extension_service.h" 26#include "chrome/browser/extensions/extension_special_storage_policy.h" 27#include "chrome/browser/notifications/desktop_notification_service.h" 28#include "chrome/browser/notifications/desktop_notification_service_factory.h" 29#include "chrome/browser/profiles/profile.h" 30#include "chrome/browser/ui/browser_list.h" 31#include "chrome/common/chrome_switches.h" 32#include "chrome/common/content_settings.h" 33#include "chrome/common/content_settings_pattern.h" 34#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 35#include "chrome/common/pref_names.h" 36#include "chrome/common/url_constants.h" 37#include "components/google/core/browser/google_util.h" 38#include "content/public/browser/notification_service.h" 39#include "content/public/browser/notification_source.h" 40#include "content/public/browser/notification_types.h" 41#include "content/public/browser/user_metrics.h" 42#include "content/public/browser/web_ui.h" 43#include "content/public/common/content_switches.h" 44#include "content/public/common/page_zoom.h" 45#include "extensions/common/extension_set.h" 46#include "extensions/common/permissions/api_permission.h" 47#include "extensions/common/permissions/permissions_data.h" 48#include "grit/generated_resources.h" 49#include "grit/locale_settings.h" 50#include "ui/base/l10n/l10n_util.h" 51 52#if defined(OS_CHROMEOS) 53#include "chrome/browser/chromeos/login/users/user_manager.h" 54#endif 55 56using base::UserMetricsAction; 57using extensions::APIPermission; 58 59namespace { 60 61struct ContentSettingsTypeNameEntry { 62 ContentSettingsType type; 63 const char* name; 64}; 65 66// Maps from a secondary pattern to a setting. 67typedef std::map<ContentSettingsPattern, ContentSetting> 68 OnePatternSettings; 69// Maps from a primary pattern/source pair to a OnePatternSettings. All the 70// mappings in OnePatternSettings share the given primary pattern and source. 71typedef std::map<std::pair<ContentSettingsPattern, std::string>, 72 OnePatternSettings> 73 AllPatternsSettings; 74 75// The AppFilter is used in AddExceptionsGrantedByHostedApps() to choose 76// extensions which should have their extent displayed. 77typedef bool (*AppFilter)(const extensions::Extension& app, Profile* profile); 78 79const char kExceptionsLearnMoreUrl[] = 80 "https://support.google.com/chrome/?p=settings_manage_exceptions"; 81 82const char* kSetting = "setting"; 83const char* kOrigin = "origin"; 84const char* kSource = "source"; 85const char* kAppName = "appName"; 86const char* kAppId = "appId"; 87const char* kEmbeddingOrigin = "embeddingOrigin"; 88const char* kPreferencesSource = "preference"; 89const char* kVideoSetting = "video"; 90const char* kZoom = "zoom"; 91 92const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { 93 {CONTENT_SETTINGS_TYPE_COOKIES, "cookies"}, 94 {CONTENT_SETTINGS_TYPE_IMAGES, "images"}, 95 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, "javascript"}, 96 {CONTENT_SETTINGS_TYPE_PLUGINS, "plugins"}, 97 {CONTENT_SETTINGS_TYPE_POPUPS, "popups"}, 98 {CONTENT_SETTINGS_TYPE_GEOLOCATION, "location"}, 99 {CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "notifications"}, 100 {CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, "auto-select-certificate"}, 101 {CONTENT_SETTINGS_TYPE_FULLSCREEN, "fullscreen"}, 102 {CONTENT_SETTINGS_TYPE_MOUSELOCK, "mouselock"}, 103 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, "register-protocol-handler"}, 104 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, "media-stream"}, 105 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, "media-stream-mic"}, 106 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, "media-stream-camera"}, 107 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, "ppapi-broker"}, 108 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, "multiple-automatic-downloads"}, 109 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, "midi-sysex"}, 110#if defined(OS_CHROMEOS) 111 {CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, "protectedContent"}, 112#endif 113}; 114 115// A pseudo content type. We use it to display data like a content setting even 116// though it is not a real content setting. 117const char* kZoomContentType = "zoomlevels"; 118 119ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) { 120 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) { 121 if (name == kContentSettingsTypeGroupNames[i].name) 122 return kContentSettingsTypeGroupNames[i].type; 123 } 124 125 NOTREACHED() << name << " is not a recognized content settings type."; 126 return CONTENT_SETTINGS_TYPE_DEFAULT; 127} 128 129std::string ContentSettingToString(ContentSetting setting) { 130 switch (setting) { 131 case CONTENT_SETTING_ALLOW: 132 return "allow"; 133 case CONTENT_SETTING_ASK: 134 return "ask"; 135 case CONTENT_SETTING_BLOCK: 136 return "block"; 137 case CONTENT_SETTING_SESSION_ONLY: 138 return "session"; 139 case CONTENT_SETTING_DEFAULT: 140 return "default"; 141 case CONTENT_SETTING_NUM_SETTINGS: 142 NOTREACHED(); 143 } 144 145 return std::string(); 146} 147 148ContentSetting ContentSettingFromString(const std::string& name) { 149 if (name == "allow") 150 return CONTENT_SETTING_ALLOW; 151 if (name == "ask") 152 return CONTENT_SETTING_ASK; 153 if (name == "block") 154 return CONTENT_SETTING_BLOCK; 155 if (name == "session") 156 return CONTENT_SETTING_SESSION_ONLY; 157 158 NOTREACHED() << name << " is not a recognized content setting."; 159 return CONTENT_SETTING_DEFAULT; 160} 161 162// Create a DictionaryValue* that will act as a data source for a single row 163// in a HostContentSettingsMap-controlled exceptions table (e.g., cookies). 164// Ownership of the pointer is passed to the caller. 165base::DictionaryValue* GetExceptionForPage( 166 const ContentSettingsPattern& pattern, 167 const ContentSettingsPattern& secondary_pattern, 168 const ContentSetting& setting, 169 const std::string& provider_name) { 170 base::DictionaryValue* exception = new base::DictionaryValue(); 171 exception->SetString(kOrigin, pattern.ToString()); 172 exception->SetString(kEmbeddingOrigin, 173 secondary_pattern == ContentSettingsPattern::Wildcard() ? 174 std::string() : 175 secondary_pattern.ToString()); 176 exception->SetString(kSetting, ContentSettingToString(setting)); 177 exception->SetString(kSource, provider_name); 178 return exception; 179} 180 181// Create a DictionaryValue* that will act as a data source for a single row 182// in the Geolocation exceptions table. Ownership of the pointer is passed to 183// the caller. 184base::DictionaryValue* GetGeolocationExceptionForPage( 185 const ContentSettingsPattern& origin, 186 const ContentSettingsPattern& embedding_origin, 187 ContentSetting setting) { 188 base::DictionaryValue* exception = new base::DictionaryValue(); 189 exception->SetString(kSetting, ContentSettingToString(setting)); 190 exception->SetString(kOrigin, origin.ToString()); 191 exception->SetString(kEmbeddingOrigin, embedding_origin.ToString()); 192 return exception; 193} 194 195// Create a DictionaryValue* that will act as a data source for a single row 196// in the desktop notifications exceptions table. Ownership of the pointer is 197// passed to the caller. 198base::DictionaryValue* GetNotificationExceptionForPage( 199 const ContentSettingsPattern& pattern, 200 ContentSetting setting, 201 const std::string& provider_name) { 202 base::DictionaryValue* exception = new base::DictionaryValue(); 203 exception->SetString(kSetting, ContentSettingToString(setting)); 204 exception->SetString(kOrigin, pattern.ToString()); 205 exception->SetString(kSource, provider_name); 206 return exception; 207} 208 209// Returns true whenever the |extension| is hosted and has |permission|. 210// Must have the AppFilter signature. 211template <APIPermission::ID permission> 212bool HostedAppHasPermission( 213 const extensions::Extension& extension, Profile* /*profile*/) { 214 return extension.is_hosted_app() && 215 extension.permissions_data()->HasAPIPermission(permission); 216} 217 218// Add an "Allow"-entry to the list of |exceptions| for a |url_pattern| from 219// the web extent of a hosted |app|. 220void AddExceptionForHostedApp(const std::string& url_pattern, 221 const extensions::Extension& app, base::ListValue* exceptions) { 222 base::DictionaryValue* exception = new base::DictionaryValue(); 223 exception->SetString(kSetting, ContentSettingToString(CONTENT_SETTING_ALLOW)); 224 exception->SetString(kOrigin, url_pattern); 225 exception->SetString(kEmbeddingOrigin, url_pattern); 226 exception->SetString(kSource, "HostedApp"); 227 exception->SetString(kAppName, app.name()); 228 exception->SetString(kAppId, app.id()); 229 exceptions->Append(exception); 230} 231 232// Asks the |profile| for hosted apps which have the |permission| set, and 233// adds their web extent and launch URL to the |exceptions| list. 234void AddExceptionsGrantedByHostedApps( 235 Profile* profile, AppFilter app_filter, base::ListValue* exceptions) { 236 const ExtensionService* extension_service = profile->GetExtensionService(); 237 // After ExtensionSystem::Init has been called at the browser's start, 238 // GetExtensionService() should not return NULL, so this is safe: 239 const extensions::ExtensionSet* extensions = extension_service->extensions(); 240 241 for (extensions::ExtensionSet::const_iterator extension = extensions->begin(); 242 extension != extensions->end(); ++extension) { 243 if (!app_filter(*extension->get(), profile)) 244 continue; 245 246 extensions::URLPatternSet web_extent = (*extension)->web_extent(); 247 // Add patterns from web extent. 248 for (extensions::URLPatternSet::const_iterator pattern = web_extent.begin(); 249 pattern != web_extent.end(); ++pattern) { 250 std::string url_pattern = pattern->GetAsString(); 251 AddExceptionForHostedApp(url_pattern, *extension->get(), exceptions); 252 } 253 // Retrieve the launch URL. 254 GURL launch_url = 255 extensions::AppLaunchInfo::GetLaunchWebURL(extension->get()); 256 // Skip adding the launch URL if it is part of the web extent. 257 if (web_extent.MatchesURL(launch_url)) 258 continue; 259 AddExceptionForHostedApp(launch_url.spec(), *extension->get(), exceptions); 260 } 261} 262 263// Sort ZoomLevelChanges by host and scheme 264// (a.com < http://a.com < https://a.com < b.com). 265bool HostZoomSort(const content::HostZoomMap::ZoomLevelChange& a, 266 const content::HostZoomMap::ZoomLevelChange& b) { 267 return a.host == b.host ? a.scheme < b.scheme : a.host < b.host; 268} 269 270} // namespace 271 272namespace options { 273 274ContentSettingsHandler::MediaSettingsInfo::MediaSettingsInfo() 275 : flash_default_setting(CONTENT_SETTING_DEFAULT), 276 flash_settings_initialized(false), 277 last_flash_refresh_request_id(0), 278 show_flash_default_link(false), 279 show_flash_exceptions_link(false), 280 default_setting(CONTENT_SETTING_DEFAULT), 281 policy_disable_audio(false), 282 policy_disable_video(false), 283 default_setting_initialized(false), 284 exceptions_initialized(false) { 285} 286 287ContentSettingsHandler::MediaSettingsInfo::~MediaSettingsInfo() { 288} 289 290ContentSettingsHandler::ContentSettingsHandler() { 291} 292 293ContentSettingsHandler::~ContentSettingsHandler() { 294} 295 296void ContentSettingsHandler::GetLocalizedValues( 297 base::DictionaryValue* localized_strings) { 298 DCHECK(localized_strings); 299 300 static OptionsStringResource resources[] = { 301 { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON }, 302 { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON }, 303 { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON }, 304 { "askException", IDS_EXCEPTIONS_ASK_BUTTON }, 305 { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL }, 306 { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS }, 307 { "manageExceptions", IDS_EXCEPTIONS_MANAGE }, 308 { "manage_handlers", IDS_HANDLERS_MANAGE }, 309 { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER }, 310 { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER }, 311 { "exceptionZoomHeader", IDS_EXCEPTIONS_ZOOM_HEADER }, 312 { "embeddedOnHost", IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST }, 313 // Cookies filter. 314 { "cookies_tab_label", IDS_COOKIES_TAB_LABEL }, 315 { "cookies_header", IDS_COOKIES_HEADER }, 316 { "cookies_allow", IDS_COOKIES_ALLOW_RADIO }, 317 { "cookies_block", IDS_COOKIES_BLOCK_RADIO }, 318 { "cookies_session_only", IDS_COOKIES_SESSION_ONLY_RADIO }, 319 { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX }, 320 { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX }, 321 { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX }, 322 { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON }, 323 { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS }, 324 { "flash_storage_url", IDS_FLASH_STORAGE_URL }, 325#if defined(ENABLE_GOOGLE_NOW) 326 { "googleGeolocationAccessEnable", 327 IDS_GEOLOCATION_GOOGLE_ACCESS_ENABLE_CHKBOX }, 328#endif 329 // Image filter. 330 { "images_tab_label", IDS_IMAGES_TAB_LABEL }, 331 { "images_header", IDS_IMAGES_HEADER }, 332 { "images_allow", IDS_IMAGES_LOAD_RADIO }, 333 { "images_block", IDS_IMAGES_NOLOAD_RADIO }, 334 // JavaScript filter. 335 { "javascript_tab_label", IDS_JAVASCRIPT_TAB_LABEL }, 336 { "javascript_header", IDS_JAVASCRIPT_HEADER }, 337 { "javascript_allow", IDS_JS_ALLOW_RADIO }, 338 { "javascript_block", IDS_JS_DONOTALLOW_RADIO }, 339 // Plug-ins filter. 340 { "plugins_tab_label", IDS_PLUGIN_TAB_LABEL }, 341 { "plugins_header", IDS_PLUGIN_HEADER }, 342 { "plugins_ask", IDS_PLUGIN_ASK_RADIO }, 343 { "plugins_allow", IDS_PLUGIN_LOAD_RADIO }, 344 { "plugins_block", IDS_PLUGIN_NOLOAD_RADIO }, 345 { "disableIndividualPlugins", IDS_PLUGIN_SELECTIVE_DISABLE }, 346 // Pop-ups filter. 347 { "popups_tab_label", IDS_POPUP_TAB_LABEL }, 348 { "popups_header", IDS_POPUP_HEADER }, 349 { "popups_allow", IDS_POPUP_ALLOW_RADIO }, 350 { "popups_block", IDS_POPUP_BLOCK_RADIO }, 351 // Location filter. 352 { "location_tab_label", IDS_GEOLOCATION_TAB_LABEL }, 353 { "location_header", IDS_GEOLOCATION_HEADER }, 354 { "location_allow", IDS_GEOLOCATION_ALLOW_RADIO }, 355 { "location_ask", IDS_GEOLOCATION_ASK_RADIO }, 356 { "location_block", IDS_GEOLOCATION_BLOCK_RADIO }, 357 { "set_by", IDS_GEOLOCATION_SET_BY_HOVER }, 358 // Notifications filter. 359 { "notifications_tab_label", IDS_NOTIFICATIONS_TAB_LABEL }, 360 { "notifications_header", IDS_NOTIFICATIONS_HEADER }, 361 { "notifications_allow", IDS_NOTIFICATIONS_ALLOW_RADIO }, 362 { "notifications_ask", IDS_NOTIFICATIONS_ASK_RADIO }, 363 { "notifications_block", IDS_NOTIFICATIONS_BLOCK_RADIO }, 364 // Fullscreen filter. 365 { "fullscreen_tab_label", IDS_FULLSCREEN_TAB_LABEL }, 366 { "fullscreen_header", IDS_FULLSCREEN_HEADER }, 367 // Mouse Lock filter. 368 { "mouselock_tab_label", IDS_MOUSE_LOCK_TAB_LABEL }, 369 { "mouselock_header", IDS_MOUSE_LOCK_HEADER }, 370 { "mouselock_allow", IDS_MOUSE_LOCK_ALLOW_RADIO }, 371 { "mouselock_ask", IDS_MOUSE_LOCK_ASK_RADIO }, 372 { "mouselock_block", IDS_MOUSE_LOCK_BLOCK_RADIO }, 373#if defined(OS_CHROMEOS) || defined(OS_WIN) 374 // Protected Content filter 375 { "protectedContentTabLabel", IDS_PROTECTED_CONTENT_TAB_LABEL }, 376 { "protectedContentInfo", IDS_PROTECTED_CONTENT_INFO }, 377 { "protectedContentEnable", IDS_PROTECTED_CONTENT_ENABLE }, 378 { "protectedContent_header", IDS_PROTECTED_CONTENT_HEADER }, 379#endif // defined(OS_CHROMEOS) || defined(OS_WIN) 380 // Media stream capture device filter. 381 { "mediaStreamTabLabel", IDS_MEDIA_STREAM_TAB_LABEL }, 382 { "media-stream_header", IDS_MEDIA_STREAM_HEADER }, 383 { "mediaStreamAsk", IDS_MEDIA_STREAM_ASK_RADIO }, 384 { "mediaStreamBlock", IDS_MEDIA_STREAM_BLOCK_RADIO }, 385 { "mediaStreamAudioAsk", IDS_MEDIA_STREAM_ASK_AUDIO_ONLY_RADIO }, 386 { "mediaStreamAudioBlock", IDS_MEDIA_STREAM_BLOCK_AUDIO_ONLY_RADIO }, 387 { "mediaStreamVideoAsk", IDS_MEDIA_STREAM_ASK_VIDEO_ONLY_RADIO }, 388 { "mediaStreamVideoBlock", IDS_MEDIA_STREAM_BLOCK_VIDEO_ONLY_RADIO }, 389 { "mediaStreamBubbleAudio", IDS_MEDIA_STREAM_AUDIO_MANAGED }, 390 { "mediaStreamBubbleVideo", IDS_MEDIA_STREAM_VIDEO_MANAGED }, 391 { "mediaAudioExceptionHeader", IDS_MEDIA_AUDIO_EXCEPTION_HEADER }, 392 { "mediaVideoExceptionHeader", IDS_MEDIA_VIDEO_EXCEPTION_HEADER }, 393 { "mediaPepperFlashDefaultDivergedLabel", 394 IDS_MEDIA_PEPPER_FLASH_DEFAULT_DIVERGED_LABEL }, 395 { "mediaPepperFlashExceptionsDivergedLabel", 396 IDS_MEDIA_PEPPER_FLASH_EXCEPTIONS_DIVERGED_LABEL }, 397 { "mediaPepperFlashChangeLink", IDS_MEDIA_PEPPER_FLASH_CHANGE_LINK }, 398 { "mediaPepperFlashGlobalPrivacyURL", IDS_FLASH_GLOBAL_PRIVACY_URL }, 399 { "mediaPepperFlashWebsitePrivacyURL", IDS_FLASH_WEBSITE_PRIVACY_URL }, 400 // PPAPI broker filter. 401 { "ppapi-broker_header", IDS_PPAPI_BROKER_HEADER }, 402 { "ppapiBrokerTabLabel", IDS_PPAPI_BROKER_TAB_LABEL }, 403 { "ppapi_broker_allow", IDS_PPAPI_BROKER_ALLOW_RADIO }, 404 { "ppapi_broker_ask", IDS_PPAPI_BROKER_ASK_RADIO }, 405 { "ppapi_broker_block", IDS_PPAPI_BROKER_BLOCK_RADIO }, 406 // Multiple automatic downloads 407 { "multiple-automatic-downloads_header", 408 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL }, 409 { "multiple-automatic-downloads_allow", 410 IDS_AUTOMATIC_DOWNLOADS_ALLOW_RADIO }, 411 { "multiple-automatic-downloads_ask", 412 IDS_AUTOMATIC_DOWNLOADS_ASK_RADIO }, 413 { "multiple-automatic-downloads_block", 414 IDS_AUTOMATIC_DOWNLOADS_BLOCK_RADIO }, 415 // MIDI system exclusive messages 416 { "midi-sysex_header", IDS_MIDI_SYSEX_TAB_LABEL }, 417 { "midiSysExAllow", IDS_MIDI_SYSEX_ALLOW_RADIO }, 418 { "midiSysExAsk", IDS_MIDI_SYSEX_ASK_RADIO }, 419 { "midiSysExBlock", IDS_MIDI_SYSEX_BLOCK_RADIO }, 420 { "zoomlevels_header", IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL }, 421 { "zoomLevelsManage", IDS_ZOOMLEVELS_MANAGE_BUTTON }, 422 }; 423 424 RegisterStrings(localized_strings, resources, arraysize(resources)); 425 RegisterTitle(localized_strings, "contentSettingsPage", 426 IDS_CONTENT_SETTINGS_TITLE); 427 428 // Register titles for each of the individual settings whose exception 429 // dialogs will be processed by |ContentSettingsHandler|. 430 RegisterTitle(localized_strings, "cookies", 431 IDS_COOKIES_TAB_LABEL); 432 RegisterTitle(localized_strings, "images", 433 IDS_IMAGES_TAB_LABEL); 434 RegisterTitle(localized_strings, "javascript", 435 IDS_JAVASCRIPT_TAB_LABEL); 436 RegisterTitle(localized_strings, "plugins", 437 IDS_PLUGIN_TAB_LABEL); 438 RegisterTitle(localized_strings, "popups", 439 IDS_POPUP_TAB_LABEL); 440 RegisterTitle(localized_strings, "location", 441 IDS_GEOLOCATION_TAB_LABEL); 442 RegisterTitle(localized_strings, "notifications", 443 IDS_NOTIFICATIONS_TAB_LABEL); 444 RegisterTitle(localized_strings, "fullscreen", 445 IDS_FULLSCREEN_TAB_LABEL); 446 RegisterTitle(localized_strings, "mouselock", 447 IDS_MOUSE_LOCK_TAB_LABEL); 448#if defined(OS_CHROMEOS) 449 RegisterTitle(localized_strings, "protectedContent", 450 IDS_PROTECTED_CONTENT_TAB_LABEL); 451#endif 452 RegisterTitle(localized_strings, "media-stream", 453 IDS_MEDIA_STREAM_TAB_LABEL); 454 RegisterTitle(localized_strings, "ppapi-broker", 455 IDS_PPAPI_BROKER_TAB_LABEL); 456 RegisterTitle(localized_strings, "multiple-automatic-downloads", 457 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL); 458 RegisterTitle(localized_strings, "midi-sysex", 459 IDS_MIDI_SYSEX_TAB_LABEL); 460 RegisterTitle(localized_strings, "zoomlevels", 461 IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL); 462 463 localized_strings->SetString("exceptionsLearnMoreUrl", 464 kExceptionsLearnMoreUrl); 465} 466 467void ContentSettingsHandler::InitializeHandler() { 468 notification_registrar_.Add( 469 this, chrome::NOTIFICATION_PROFILE_CREATED, 470 content::NotificationService::AllSources()); 471 notification_registrar_.Add( 472 this, chrome::NOTIFICATION_PROFILE_DESTROYED, 473 content::NotificationService::AllSources()); 474 475 notification_registrar_.Add( 476 this, chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED, 477 content::NotificationService::AllSources()); 478 notification_registrar_.Add( 479 this, chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED, 480 content::NotificationService::AllSources()); 481 Profile* profile = Profile::FromWebUI(web_ui()); 482 notification_registrar_.Add( 483 this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, 484 content::Source<Profile>(profile)); 485 486 PrefService* prefs = profile->GetPrefs(); 487 pref_change_registrar_.Init(prefs); 488 pref_change_registrar_.Add( 489 prefs::kPepperFlashSettingsEnabled, 490 base::Bind(&ContentSettingsHandler::OnPepperFlashPrefChanged, 491 base::Unretained(this))); 492 pref_change_registrar_.Add( 493 prefs::kAudioCaptureAllowed, 494 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView, 495 base::Unretained(this))); 496 pref_change_registrar_.Add( 497 prefs::kVideoCaptureAllowed, 498 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView, 499 base::Unretained(this))); 500 pref_change_registrar_.Add( 501 prefs::kEnableDRM, 502 base::Bind( 503 &ContentSettingsHandler::UpdateProtectedContentExceptionsButton, 504 base::Unretained(this))); 505 506 content::HostZoomMap* host_zoom_map = 507 content::HostZoomMap::GetForBrowserContext(profile); 508 host_zoom_map_subscription_ = 509 host_zoom_map->AddZoomLevelChangedCallback( 510 base::Bind(&ContentSettingsHandler::OnZoomLevelChanged, 511 base::Unretained(this))); 512 513 flash_settings_manager_.reset(new PepperFlashSettingsManager(this, profile)); 514} 515 516void ContentSettingsHandler::InitializePage() { 517 media_settings_ = MediaSettingsInfo(); 518 RefreshFlashMediaSettings(); 519 520 UpdateHandlersEnabledRadios(); 521 UpdateAllExceptionsViewsFromModel(); 522 UpdateProtectedContentExceptionsButton(); 523} 524 525void ContentSettingsHandler::Observe( 526 int type, 527 const content::NotificationSource& source, 528 const content::NotificationDetails& details) { 529 switch (type) { 530 case chrome::NOTIFICATION_PROFILE_DESTROYED: { 531 if (content::Source<Profile>(source).ptr()->IsOffTheRecord()) { 532 web_ui()->CallJavascriptFunction( 533 "ContentSettingsExceptionsArea.OTRProfileDestroyed"); 534 } 535 break; 536 } 537 538 case chrome::NOTIFICATION_PROFILE_CREATED: { 539 if (content::Source<Profile>(source).ptr()->IsOffTheRecord()) 540 UpdateAllOTRExceptionsViewsFromModel(); 541 break; 542 } 543 544 case chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED: { 545 // Filter out notifications from other profiles. 546 HostContentSettingsMap* map = 547 content::Source<HostContentSettingsMap>(source).ptr(); 548 if (map != GetContentSettingsMap() && 549 map != GetOTRContentSettingsMap()) 550 break; 551 552 const ContentSettingsDetails* settings_details = 553 content::Details<const ContentSettingsDetails>(details).ptr(); 554 555 // TODO(estade): we pretend update_all() is always true. 556 if (settings_details->update_all_types()) 557 UpdateAllExceptionsViewsFromModel(); 558 else 559 UpdateExceptionsViewFromModel(settings_details->type()); 560 break; 561 } 562 563 case chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED: { 564 UpdateNotificationExceptionsView(); 565 break; 566 } 567 568 case chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED: { 569 UpdateHandlersEnabledRadios(); 570 break; 571 } 572 } 573} 574 575void ContentSettingsHandler::OnGetPermissionSettingsCompleted( 576 uint32 request_id, 577 bool success, 578 PP_Flash_BrowserOperations_Permission default_permission, 579 const ppapi::FlashSiteSettings& sites) { 580 if (success && request_id == media_settings_.last_flash_refresh_request_id) { 581 media_settings_.flash_settings_initialized = true; 582 media_settings_.flash_default_setting = 583 PepperFlashContentSettingsUtils::FlashPermissionToContentSetting( 584 default_permission); 585 PepperFlashContentSettingsUtils::FlashSiteSettingsToMediaExceptions( 586 sites, &media_settings_.flash_exceptions); 587 PepperFlashContentSettingsUtils::SortMediaExceptions( 588 &media_settings_.flash_exceptions); 589 590 UpdateFlashMediaLinksVisibility(); 591 } 592} 593 594void ContentSettingsHandler::UpdateSettingDefaultFromModel( 595 ContentSettingsType type) { 596 base::DictionaryValue filter_settings; 597 std::string provider_id; 598 filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value", 599 GetSettingDefaultFromModel(type, &provider_id)); 600 filter_settings.SetString( 601 ContentSettingsTypeToGroupName(type) + ".managedBy", provider_id); 602 603 web_ui()->CallJavascriptFunction( 604 "ContentSettings.setContentFilterSettingsValue", filter_settings); 605} 606 607void ContentSettingsHandler::UpdateMediaSettingsView() { 608 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); 609 bool audio_disabled = !prefs->GetBoolean(prefs::kAudioCaptureAllowed) && 610 prefs->IsManagedPreference(prefs::kAudioCaptureAllowed); 611 bool video_disabled = !prefs->GetBoolean(prefs::kVideoCaptureAllowed) && 612 prefs->IsManagedPreference(prefs::kVideoCaptureAllowed); 613 614 media_settings_.policy_disable_audio = audio_disabled; 615 media_settings_.policy_disable_video = video_disabled; 616 media_settings_.default_setting = 617 GetContentSettingsMap()->GetDefaultContentSetting( 618 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL); 619 media_settings_.default_setting_initialized = true; 620 UpdateFlashMediaLinksVisibility(); 621 622 base::DictionaryValue media_ui_settings; 623 media_ui_settings.SetBoolean("cameraDisabled", video_disabled); 624 media_ui_settings.SetBoolean("micDisabled", audio_disabled); 625 626 // In case only video is enabled change the text appropriately. 627 if (audio_disabled && !video_disabled) { 628 media_ui_settings.SetString("askText", "mediaStreamVideoAsk"); 629 media_ui_settings.SetString("blockText", "mediaStreamVideoBlock"); 630 media_ui_settings.SetBoolean("showBubble", true); 631 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleAudio"); 632 633 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI", 634 media_ui_settings); 635 return; 636 } 637 638 // In case only audio is enabled change the text appropriately. 639 if (video_disabled && !audio_disabled) { 640 base::DictionaryValue media_ui_settings; 641 media_ui_settings.SetString("askText", "mediaStreamAudioAsk"); 642 media_ui_settings.SetString("blockText", "mediaStreamAudioBlock"); 643 media_ui_settings.SetBoolean("showBubble", true); 644 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleVideo"); 645 646 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI", 647 media_ui_settings); 648 return; 649 } 650 651 if (audio_disabled && video_disabled) { 652 // Fake policy controlled default because the user can not change anything 653 // until both audio and video are blocked. 654 base::DictionaryValue filter_settings; 655 std::string group_name = 656 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM); 657 filter_settings.SetString(group_name + ".value", 658 ContentSettingToString(CONTENT_SETTING_BLOCK)); 659 filter_settings.SetString(group_name + ".managedBy", "policy"); 660 web_ui()->CallJavascriptFunction( 661 "ContentSettings.setContentFilterSettingsValue", filter_settings); 662 } 663 664 media_ui_settings.SetString("askText", "mediaStreamAsk"); 665 media_ui_settings.SetString("blockText", "mediaStreamBlock"); 666 media_ui_settings.SetBoolean("showBubble", false); 667 media_ui_settings.SetString("bubbleText", std::string()); 668 669 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI", 670 media_ui_settings); 671} 672 673std::string ContentSettingsHandler::GetSettingDefaultFromModel( 674 ContentSettingsType type, std::string* provider_id) { 675 Profile* profile = Profile::FromWebUI(web_ui()); 676 ContentSetting default_setting; 677 if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { 678 default_setting = 679 DesktopNotificationServiceFactory::GetForProfile(profile)-> 680 GetDefaultContentSetting(provider_id); 681 } else { 682 default_setting = 683 profile->GetHostContentSettingsMap()-> 684 GetDefaultContentSetting(type, provider_id); 685 } 686 687 return ContentSettingToString(default_setting); 688} 689 690void ContentSettingsHandler::UpdateHandlersEnabledRadios() { 691 base::FundamentalValue handlers_enabled( 692 GetProtocolHandlerRegistry()->enabled()); 693 694 web_ui()->CallJavascriptFunction( 695 "ContentSettings.updateHandlersEnabledRadios", 696 handlers_enabled); 697} 698 699void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() { 700 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1; 701 type < CONTENT_SETTINGS_NUM_TYPES; ++type) { 702 UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type)); 703 } 704 // Zoom levels are not actually a content type so we need to handle them 705 // separately. 706 UpdateZoomLevelsExceptionsView(); 707} 708 709void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() { 710 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1; 711 type < CONTENT_SETTINGS_NUM_TYPES; ++type) { 712 UpdateOTRExceptionsViewFromModel(static_cast<ContentSettingsType>(type)); 713 } 714} 715 716void ContentSettingsHandler::UpdateExceptionsViewFromModel( 717 ContentSettingsType type) { 718 switch (type) { 719 case CONTENT_SETTINGS_TYPE_GEOLOCATION: 720 UpdateGeolocationExceptionsView(); 721 break; 722 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: 723 UpdateNotificationExceptionsView(); 724 break; 725 case CONTENT_SETTINGS_TYPE_MEDIASTREAM: 726 UpdateMediaSettingsView(); 727 break; 728 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: 729 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: 730 UpdateMediaExceptionsView(); 731 break; 732 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT: 733 // We don't yet support exceptions for mixed scripting. 734 break; 735 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE: 736 // The content settings type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE 737 // is supposed to be set by policy only. Hence there is no user facing UI 738 // for this content type and we skip it here. 739 break; 740 case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS: 741 // The RPH settings are retrieved separately. 742 break; 743 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX: 744 UpdateMIDISysExExceptionsView(); 745 break; 746#if defined(OS_WIN) 747 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP: 748 break; 749#endif 750 default: 751 UpdateExceptionsViewFromHostContentSettingsMap(type); 752 break; 753 } 754} 755 756void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel( 757 ContentSettingsType type) { 758 switch (type) { 759 case CONTENT_SETTINGS_TYPE_GEOLOCATION: 760 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: 761 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE: 762 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT: 763#if defined(OS_WIN) 764 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP: 765#endif 766 case CONTENT_SETTINGS_TYPE_MEDIASTREAM: 767 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: 768 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: 769 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS: 770 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX: 771 break; 772 default: 773 UpdateExceptionsViewFromOTRHostContentSettingsMap(type); 774 break; 775 } 776} 777 778// TODO(estade): merge with GetExceptionsFromHostContentSettingsMap. 779void ContentSettingsHandler::UpdateGeolocationExceptionsView() { 780 Profile* profile = Profile::FromWebUI(web_ui()); 781 HostContentSettingsMap* map = profile->GetHostContentSettingsMap(); 782 783 ContentSettingsForOneType all_settings; 784 map->GetSettingsForOneType( 785 CONTENT_SETTINGS_TYPE_GEOLOCATION, 786 std::string(), 787 &all_settings); 788 789 // Group geolocation settings by primary_pattern. 790 AllPatternsSettings all_patterns_settings; 791 for (ContentSettingsForOneType::iterator i = all_settings.begin(); 792 i != all_settings.end(); ++i) { 793 // Don't add default settings. 794 if (i->primary_pattern == ContentSettingsPattern::Wildcard() && 795 i->secondary_pattern == ContentSettingsPattern::Wildcard() && 796 i->source != kPreferencesSource) { 797 continue; 798 } 799 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)] 800 [i->secondary_pattern] = i->setting; 801 } 802 803 base::ListValue exceptions; 804 AddExceptionsGrantedByHostedApps( 805 profile, 806 HostedAppHasPermission<APIPermission::kGeolocation>, 807 &exceptions); 808 809 for (AllPatternsSettings::iterator i = all_patterns_settings.begin(); 810 i != all_patterns_settings.end(); ++i) { 811 const ContentSettingsPattern& primary_pattern = i->first.first; 812 const OnePatternSettings& one_settings = i->second; 813 814 OnePatternSettings::const_iterator parent = 815 one_settings.find(primary_pattern); 816 817 // Add the "parent" entry for the non-embedded setting. 818 ContentSetting parent_setting = 819 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second; 820 exceptions.Append(GetGeolocationExceptionForPage(primary_pattern, 821 primary_pattern, 822 parent_setting)); 823 824 // Add the "children" for any embedded settings. 825 for (OnePatternSettings::const_iterator j = one_settings.begin(); 826 j != one_settings.end(); 827 ++j) { 828 // Skip the non-embedded setting which we already added above. 829 if (j == parent) 830 continue; 831 832 exceptions.Append(GetGeolocationExceptionForPage( 833 primary_pattern, j->first, j->second)); 834 } 835 } 836 837 base::StringValue type_string( 838 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION)); 839 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", 840 type_string, exceptions); 841 842 // This is mainly here to keep this function ideologically parallel to 843 // UpdateExceptionsViewFromHostContentSettingsMap(). 844 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION); 845} 846 847void ContentSettingsHandler::UpdateNotificationExceptionsView() { 848 Profile* profile = Profile::FromWebUI(web_ui()); 849 DesktopNotificationService* service = 850 DesktopNotificationServiceFactory::GetForProfile(profile); 851 852 ContentSettingsForOneType settings; 853 service->GetNotificationsSettings(&settings); 854 855 base::ListValue exceptions; 856 AddExceptionsGrantedByHostedApps(profile, 857 HostedAppHasPermission<APIPermission::kNotification>, 858 &exceptions); 859 860 for (ContentSettingsForOneType::const_iterator i = 861 settings.begin(); 862 i != settings.end(); 863 ++i) { 864 // Don't add default settings. 865 if (i->primary_pattern == ContentSettingsPattern::Wildcard() && 866 i->secondary_pattern == ContentSettingsPattern::Wildcard() && 867 i->source != kPreferencesSource) { 868 continue; 869 } 870 871 exceptions.Append( 872 GetNotificationExceptionForPage(i->primary_pattern, i->setting, 873 i->source)); 874 } 875 876 base::StringValue type_string( 877 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); 878 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", 879 type_string, exceptions); 880 881 // This is mainly here to keep this function ideologically parallel to 882 // UpdateExceptionsViewFromHostContentSettingsMap(). 883 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS); 884} 885 886void ContentSettingsHandler::UpdateMediaExceptionsView() { 887 base::ListValue media_exceptions; 888 GetExceptionsFromHostContentSettingsMap( 889 GetContentSettingsMap(), 890 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, 891 &media_exceptions); 892 893 base::ListValue video_exceptions; 894 GetExceptionsFromHostContentSettingsMap( 895 GetContentSettingsMap(), 896 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, 897 &video_exceptions); 898 899 // Merge the |video_exceptions| list to |media_exceptions| list. 900 std::map<std::string, base::DictionaryValue*> entries_map; 901 for (base::ListValue::const_iterator media_entry(media_exceptions.begin()); 902 media_entry != media_exceptions.end(); ++media_entry) { 903 base::DictionaryValue* media_dict = NULL; 904 if (!(*media_entry)->GetAsDictionary(&media_dict)) 905 NOTREACHED(); 906 907 media_dict->SetString(kVideoSetting, 908 ContentSettingToString(CONTENT_SETTING_ASK)); 909 910 std::string media_origin; 911 media_dict->GetString(kOrigin, &media_origin); 912 entries_map[media_origin] = media_dict; 913 } 914 915 for (base::ListValue::iterator video_entry = video_exceptions.begin(); 916 video_entry != video_exceptions.end(); ++video_entry) { 917 base::DictionaryValue* video_dict = NULL; 918 if (!(*video_entry)->GetAsDictionary(&video_dict)) 919 NOTREACHED(); 920 921 std::string video_origin; 922 std::string video_setting; 923 video_dict->GetString(kOrigin, &video_origin); 924 video_dict->GetString(kSetting, &video_setting); 925 926 std::map<std::string, base::DictionaryValue*>::iterator iter = 927 entries_map.find(video_origin); 928 if (iter == entries_map.end()) { 929 base::DictionaryValue* exception = new base::DictionaryValue(); 930 exception->SetString(kOrigin, video_origin); 931 exception->SetString(kSetting, 932 ContentSettingToString(CONTENT_SETTING_ASK)); 933 exception->SetString(kVideoSetting, video_setting); 934 exception->SetString(kSource, kPreferencesSource); 935 936 // Append the new entry to the list and map. 937 media_exceptions.Append(exception); 938 entries_map[video_origin] = exception; 939 } else { 940 // Modify the existing entry. 941 iter->second->SetString(kVideoSetting, video_setting); 942 } 943 } 944 945 media_settings_.exceptions.clear(); 946 for (base::ListValue::const_iterator media_entry = media_exceptions.begin(); 947 media_entry != media_exceptions.end(); ++media_entry) { 948 base::DictionaryValue* media_dict = NULL; 949 bool result = (*media_entry)->GetAsDictionary(&media_dict); 950 DCHECK(result); 951 952 std::string origin; 953 std::string audio_setting; 954 std::string video_setting; 955 media_dict->GetString(kOrigin, &origin); 956 media_dict->GetString(kSetting, &audio_setting); 957 media_dict->GetString(kVideoSetting, &video_setting); 958 media_settings_.exceptions.push_back(MediaException( 959 ContentSettingsPattern::FromString(origin), 960 ContentSettingFromString(audio_setting), 961 ContentSettingFromString(video_setting))); 962 } 963 PepperFlashContentSettingsUtils::SortMediaExceptions( 964 &media_settings_.exceptions); 965 media_settings_.exceptions_initialized = true; 966 UpdateFlashMediaLinksVisibility(); 967 968 base::StringValue type_string( 969 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM)); 970 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", 971 type_string, media_exceptions); 972 973 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MEDIASTREAM); 974} 975 976void ContentSettingsHandler::UpdateMIDISysExExceptionsView() { 977 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebMIDI)) { 978 web_ui()->CallJavascriptFunction( 979 "ContentSettings.showExperimentalWebMIDISettings", 980 base::FundamentalValue(true)); 981 } 982 983 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MIDI_SYSEX); 984 UpdateExceptionsViewFromHostContentSettingsMap( 985 CONTENT_SETTINGS_TYPE_MIDI_SYSEX); 986} 987 988void ContentSettingsHandler::UpdateZoomLevelsExceptionsView() { 989 base::ListValue zoom_levels_exceptions; 990 991 content::HostZoomMap* host_zoom_map = 992 content::HostZoomMap::GetForBrowserContext(Profile::FromWebUI(web_ui())); 993 content::HostZoomMap::ZoomLevelVector zoom_levels( 994 host_zoom_map->GetAllZoomLevels()); 995 std::sort(zoom_levels.begin(), zoom_levels.end(), HostZoomSort); 996 997 for (content::HostZoomMap::ZoomLevelVector::const_iterator i = 998 zoom_levels.begin(); 999 i != zoom_levels.end(); 1000 ++i) { 1001 scoped_ptr<base::DictionaryValue> exception(new base::DictionaryValue); 1002 switch (i->mode) { 1003 case content::HostZoomMap::ZOOM_CHANGED_FOR_HOST: 1004 exception->SetString(kOrigin, i->host); 1005 break; 1006 case content::HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST: 1007 // These are not stored in preferences and get cleared on next browser 1008 // start. Therefore, we don't care for them. 1009 break; 1010 case content::HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM: 1011 NOTREACHED(); 1012 } 1013 exception->SetString(kSetting, 1014 ContentSettingToString(CONTENT_SETTING_DEFAULT)); 1015 1016 // Calculate the zoom percent from the factor. Round up to the nearest whole 1017 // number. 1018 int zoom_percent = static_cast<int>( 1019 content::ZoomLevelToZoomFactor(i->zoom_level) * 100 + 0.5); 1020 exception->SetString( 1021 kZoom, 1022 l10n_util::GetStringFUTF16(IDS_ZOOM_PERCENT, 1023 base::IntToString16(zoom_percent))); 1024 exception->SetString(kSource, kPreferencesSource); 1025 // Append the new entry to the list and map. 1026 zoom_levels_exceptions.Append(exception.release()); 1027 } 1028 1029 base::StringValue type_string(kZoomContentType); 1030 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", 1031 type_string, zoom_levels_exceptions); 1032} 1033 1034void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap( 1035 ContentSettingsType type) { 1036 base::ListValue exceptions; 1037 GetExceptionsFromHostContentSettingsMap( 1038 GetContentSettingsMap(), type, &exceptions); 1039 base::StringValue type_string(ContentSettingsTypeToGroupName(type)); 1040 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", type_string, 1041 exceptions); 1042 1043 UpdateExceptionsViewFromOTRHostContentSettingsMap(type); 1044 1045 // TODO(koz): The default for fullscreen is always 'ask'. 1046 // http://crbug.com/104683 1047 if (type == CONTENT_SETTINGS_TYPE_FULLSCREEN) 1048 return; 1049 1050#if defined(OS_CHROMEOS) 1051 // Also the default for protected contents is managed in another place. 1052 if (type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER) 1053 return; 1054#endif 1055 1056 // The default may also have changed (we won't get a separate notification). 1057 // If it hasn't changed, this call will be harmless. 1058 UpdateSettingDefaultFromModel(type); 1059} 1060 1061void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap( 1062 ContentSettingsType type) { 1063 const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap(); 1064 if (!otr_settings_map) 1065 return; 1066 base::ListValue exceptions; 1067 GetExceptionsFromHostContentSettingsMap(otr_settings_map, type, &exceptions); 1068 base::StringValue type_string(ContentSettingsTypeToGroupName(type)); 1069 web_ui()->CallJavascriptFunction("ContentSettings.setOTRExceptions", 1070 type_string, exceptions); 1071} 1072 1073void ContentSettingsHandler::GetExceptionsFromHostContentSettingsMap( 1074 const HostContentSettingsMap* map, 1075 ContentSettingsType type, 1076 base::ListValue* exceptions) { 1077 ContentSettingsForOneType entries; 1078 map->GetSettingsForOneType(type, std::string(), &entries); 1079 // Group settings by primary_pattern. 1080 AllPatternsSettings all_patterns_settings; 1081 for (ContentSettingsForOneType::iterator i = entries.begin(); 1082 i != entries.end(); ++i) { 1083 // Don't add default settings. 1084 if (i->primary_pattern == ContentSettingsPattern::Wildcard() && 1085 i->secondary_pattern == ContentSettingsPattern::Wildcard() && 1086 i->source != kPreferencesSource) { 1087 continue; 1088 } 1089 1090 // Off-the-record HostContentSettingsMap contains incognito content settings 1091 // as well as normal content settings. Here, we use the incongnito settings 1092 // only. 1093 if (map->is_off_the_record() && !i->incognito) 1094 continue; 1095 1096 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)] 1097 [i->secondary_pattern] = i->setting; 1098 } 1099 1100 // Keep the exceptions sorted by provider so they will be displayed in 1101 // precedence order. 1102 std::vector<std::vector<base::Value*> > all_provider_exceptions; 1103 all_provider_exceptions.resize(HostContentSettingsMap::NUM_PROVIDER_TYPES); 1104 1105 for (AllPatternsSettings::iterator i = all_patterns_settings.begin(); 1106 i != all_patterns_settings.end(); 1107 ++i) { 1108 const ContentSettingsPattern& primary_pattern = i->first.first; 1109 const OnePatternSettings& one_settings = i->second; 1110 1111 // The "parent" entry either has an identical primary and secondary pattern, 1112 // or has a wildcard secondary. The two cases are indistinguishable in the 1113 // UI. 1114 OnePatternSettings::const_iterator parent = 1115 one_settings.find(primary_pattern); 1116 if (parent == one_settings.end()) 1117 parent = one_settings.find(ContentSettingsPattern::Wildcard()); 1118 1119 const std::string& source = i->first.second; 1120 std::vector<base::Value*>* this_provider_exceptions = 1121 &all_provider_exceptions.at( 1122 HostContentSettingsMap::GetProviderTypeFromSource(source)); 1123 1124 // Add the "parent" entry for the non-embedded setting. 1125 ContentSetting parent_setting = 1126 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second; 1127 const ContentSettingsPattern& secondary_pattern = 1128 parent == one_settings.end() ? primary_pattern : parent->first; 1129 this_provider_exceptions->push_back(GetExceptionForPage(primary_pattern, 1130 secondary_pattern, 1131 parent_setting, 1132 source)); 1133 1134 // Add the "children" for any embedded settings. 1135 for (OnePatternSettings::const_iterator j = one_settings.begin(); 1136 j != one_settings.end(); ++j) { 1137 // Skip the non-embedded setting which we already added above. 1138 if (j == parent) 1139 continue; 1140 1141 ContentSetting content_setting = j->second; 1142 this_provider_exceptions->push_back(GetExceptionForPage( 1143 primary_pattern, 1144 j->first, 1145 content_setting, 1146 source)); 1147 } 1148 } 1149 1150 for (size_t i = 0; i < all_provider_exceptions.size(); ++i) { 1151 for (size_t j = 0; j < all_provider_exceptions[i].size(); ++j) { 1152 exceptions->Append(all_provider_exceptions[i][j]); 1153 } 1154 } 1155} 1156 1157void ContentSettingsHandler::RemoveNotificationException( 1158 const base::ListValue* args) { 1159 Profile* profile = Profile::FromWebUI(web_ui()); 1160 std::string origin; 1161 std::string setting; 1162 bool rv = args->GetString(1, &origin); 1163 DCHECK(rv); 1164 rv = args->GetString(2, &setting); 1165 DCHECK(rv); 1166 ContentSetting content_setting = ContentSettingFromString(setting); 1167 1168 DCHECK(content_setting == CONTENT_SETTING_ALLOW || 1169 content_setting == CONTENT_SETTING_BLOCK); 1170 DesktopNotificationServiceFactory::GetForProfile(profile)-> 1171 ClearSetting(ContentSettingsPattern::FromString(origin)); 1172} 1173 1174void ContentSettingsHandler::RemoveMediaException(const base::ListValue* args) { 1175 std::string mode; 1176 bool rv = args->GetString(1, &mode); 1177 DCHECK(rv); 1178 1179 std::string pattern; 1180 rv = args->GetString(2, &pattern); 1181 DCHECK(rv); 1182 1183 HostContentSettingsMap* settings_map = 1184 mode == "normal" ? GetContentSettingsMap() : 1185 GetOTRContentSettingsMap(); 1186 if (settings_map) { 1187 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern), 1188 ContentSettingsPattern::Wildcard(), 1189 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, 1190 std::string(), 1191 NULL); 1192 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern), 1193 ContentSettingsPattern::Wildcard(), 1194 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, 1195 std::string(), 1196 NULL); 1197 } 1198} 1199 1200void ContentSettingsHandler::RemoveExceptionFromHostContentSettingsMap( 1201 const base::ListValue* args, 1202 ContentSettingsType type) { 1203 std::string mode; 1204 bool rv = args->GetString(1, &mode); 1205 DCHECK(rv); 1206 1207 std::string pattern; 1208 rv = args->GetString(2, &pattern); 1209 DCHECK(rv); 1210 1211 // The fourth argument to this handler is optional. 1212 std::string secondary_pattern; 1213 if (args->GetSize() >= 4U) { 1214 rv = args->GetString(3, &secondary_pattern); 1215 DCHECK(rv); 1216 } 1217 1218 HostContentSettingsMap* settings_map = 1219 mode == "normal" ? GetContentSettingsMap() : 1220 GetOTRContentSettingsMap(); 1221 if (settings_map) { 1222 settings_map->SetWebsiteSetting( 1223 ContentSettingsPattern::FromString(pattern), 1224 secondary_pattern.empty() ? 1225 ContentSettingsPattern::Wildcard() : 1226 ContentSettingsPattern::FromString(secondary_pattern), 1227 type, 1228 std::string(), 1229 NULL); 1230 } 1231} 1232 1233void ContentSettingsHandler::RemoveZoomLevelException( 1234 const base::ListValue* args) { 1235 std::string mode; 1236 bool rv = args->GetString(1, &mode); 1237 DCHECK(rv); 1238 1239 std::string pattern; 1240 rv = args->GetString(2, &pattern); 1241 DCHECK(rv); 1242 1243 content::HostZoomMap* host_zoom_map = 1244 content::HostZoomMap::GetForBrowserContext(Profile::FromWebUI(web_ui())); 1245 double default_level = host_zoom_map->GetDefaultZoomLevel(); 1246 host_zoom_map->SetZoomLevelForHost(pattern, default_level); 1247} 1248 1249void ContentSettingsHandler::RegisterMessages() { 1250 web_ui()->RegisterMessageCallback("setContentFilter", 1251 base::Bind(&ContentSettingsHandler::SetContentFilter, 1252 base::Unretained(this))); 1253 web_ui()->RegisterMessageCallback("removeException", 1254 base::Bind(&ContentSettingsHandler::RemoveException, 1255 base::Unretained(this))); 1256 web_ui()->RegisterMessageCallback("setException", 1257 base::Bind(&ContentSettingsHandler::SetException, 1258 base::Unretained(this))); 1259 web_ui()->RegisterMessageCallback("checkExceptionPatternValidity", 1260 base::Bind(&ContentSettingsHandler::CheckExceptionPatternValidity, 1261 base::Unretained(this))); 1262} 1263 1264void ContentSettingsHandler::ApplyWhitelist(ContentSettingsType content_type, 1265 ContentSetting default_setting) { 1266 Profile* profile = Profile::FromWebUI(web_ui()); 1267 HostContentSettingsMap* map = GetContentSettingsMap(); 1268 if (content_type != CONTENT_SETTINGS_TYPE_PLUGINS) 1269 return; 1270 const int kDefaultWhitelistVersion = 1; 1271 PrefService* prefs = profile->GetPrefs(); 1272 int version = prefs->GetInteger( 1273 prefs::kContentSettingsDefaultWhitelistVersion); 1274 if (version >= kDefaultWhitelistVersion) 1275 return; 1276 ContentSetting old_setting = 1277 map->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS, NULL); 1278 // TODO(bauerb): Remove this once the Google Talk plug-in works nicely with 1279 // click-to-play (b/6090625). 1280 if (old_setting == CONTENT_SETTING_ALLOW && 1281 default_setting == CONTENT_SETTING_ASK) { 1282 map->SetWebsiteSetting( 1283 ContentSettingsPattern::Wildcard(), 1284 ContentSettingsPattern::Wildcard(), 1285 CONTENT_SETTINGS_TYPE_PLUGINS, 1286 "google-talk", 1287 new base::FundamentalValue(CONTENT_SETTING_ALLOW)); 1288 } 1289 prefs->SetInteger(prefs::kContentSettingsDefaultWhitelistVersion, 1290 kDefaultWhitelistVersion); 1291} 1292 1293void ContentSettingsHandler::SetContentFilter(const base::ListValue* args) { 1294 DCHECK_EQ(2U, args->GetSize()); 1295 std::string group, setting; 1296 if (!(args->GetString(0, &group) && 1297 args->GetString(1, &setting))) { 1298 NOTREACHED(); 1299 return; 1300 } 1301 1302 ContentSetting default_setting = ContentSettingFromString(setting); 1303 ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group); 1304 Profile* profile = Profile::FromWebUI(web_ui()); 1305 1306#if defined(OS_CHROMEOS) 1307 // ChromeOS special case : in Guest mode settings are opened in Incognito 1308 // mode, so we need original profile to actually modify settings. 1309 if (chromeos::UserManager::Get()->IsLoggedInAsGuest()) 1310 profile = profile->GetOriginalProfile(); 1311#endif 1312 1313 if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { 1314 DesktopNotificationServiceFactory::GetForProfile(profile)-> 1315 SetDefaultContentSetting(default_setting); 1316 } else { 1317 HostContentSettingsMap* map = profile->GetHostContentSettingsMap(); 1318 ApplyWhitelist(content_type, default_setting); 1319 map->SetDefaultContentSetting(content_type, default_setting); 1320 } 1321 switch (content_type) { 1322 case CONTENT_SETTINGS_TYPE_COOKIES: 1323 content::RecordAction( 1324 UserMetricsAction("Options_DefaultCookieSettingChanged")); 1325 break; 1326 case CONTENT_SETTINGS_TYPE_IMAGES: 1327 content::RecordAction( 1328 UserMetricsAction("Options_DefaultImagesSettingChanged")); 1329 break; 1330 case CONTENT_SETTINGS_TYPE_JAVASCRIPT: 1331 content::RecordAction( 1332 UserMetricsAction("Options_DefaultJavaScriptSettingChanged")); 1333 break; 1334 case CONTENT_SETTINGS_TYPE_PLUGINS: 1335 content::RecordAction( 1336 UserMetricsAction("Options_DefaultPluginsSettingChanged")); 1337 break; 1338 case CONTENT_SETTINGS_TYPE_POPUPS: 1339 content::RecordAction( 1340 UserMetricsAction("Options_DefaultPopupsSettingChanged")); 1341 break; 1342 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: 1343 content::RecordAction( 1344 UserMetricsAction("Options_DefaultNotificationsSettingChanged")); 1345 break; 1346 case CONTENT_SETTINGS_TYPE_GEOLOCATION: 1347 content::RecordAction( 1348 UserMetricsAction("Options_DefaultGeolocationSettingChanged")); 1349 break; 1350 case CONTENT_SETTINGS_TYPE_MOUSELOCK: 1351 content::RecordAction( 1352 UserMetricsAction("Options_DefaultMouseLockSettingChanged")); 1353 break; 1354 case CONTENT_SETTINGS_TYPE_MEDIASTREAM: 1355 content::RecordAction( 1356 UserMetricsAction("Options_DefaultMediaStreamMicSettingChanged")); 1357 break; 1358 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS: 1359 content::RecordAction( 1360 UserMetricsAction("Options_DefaultMultipleAutomaticDLSettingChange")); 1361 break; 1362 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX: 1363 content::RecordAction( 1364 UserMetricsAction("Options_DefaultMIDISysExSettingChanged")); 1365 break; 1366 default: 1367 break; 1368 } 1369} 1370 1371void ContentSettingsHandler::RemoveException(const base::ListValue* args) { 1372 std::string type_string; 1373 CHECK(args->GetString(0, &type_string)); 1374 1375 // Zoom levels are no actual content type so we need to handle them 1376 // separately. They would not be recognized by 1377 // ContentSettingsTypeFromGroupName. 1378 if (type_string == kZoomContentType) { 1379 RemoveZoomLevelException(args); 1380 return; 1381 } 1382 1383 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string); 1384 switch (type) { 1385 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: 1386 RemoveNotificationException(args); 1387 break; 1388 case CONTENT_SETTINGS_TYPE_MEDIASTREAM: 1389 RemoveMediaException(args); 1390 break; 1391 default: 1392 RemoveExceptionFromHostContentSettingsMap(args, type); 1393 break; 1394 } 1395} 1396 1397void ContentSettingsHandler::SetException(const base::ListValue* args) { 1398 std::string type_string; 1399 CHECK(args->GetString(0, &type_string)); 1400 std::string mode; 1401 CHECK(args->GetString(1, &mode)); 1402 std::string pattern; 1403 CHECK(args->GetString(2, &pattern)); 1404 std::string setting; 1405 CHECK(args->GetString(3, &setting)); 1406 1407 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string); 1408 if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION || 1409 type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS || 1410 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM || 1411 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC || 1412 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) { 1413 NOTREACHED(); 1414 } else { 1415 HostContentSettingsMap* settings_map = 1416 mode == "normal" ? GetContentSettingsMap() : 1417 GetOTRContentSettingsMap(); 1418 1419 // The settings map could be null if the mode was OTR but the OTR profile 1420 // got destroyed before we received this message. 1421 if (!settings_map) 1422 return; 1423 settings_map->SetContentSetting(ContentSettingsPattern::FromString(pattern), 1424 ContentSettingsPattern::Wildcard(), 1425 type, 1426 std::string(), 1427 ContentSettingFromString(setting)); 1428 } 1429} 1430 1431void ContentSettingsHandler::CheckExceptionPatternValidity( 1432 const base::ListValue* args) { 1433 std::string type_string; 1434 CHECK(args->GetString(0, &type_string)); 1435 std::string mode_string; 1436 CHECK(args->GetString(1, &mode_string)); 1437 std::string pattern_string; 1438 CHECK(args->GetString(2, &pattern_string)); 1439 1440 ContentSettingsPattern pattern = 1441 ContentSettingsPattern::FromString(pattern_string); 1442 1443 web_ui()->CallJavascriptFunction( 1444 "ContentSettings.patternValidityCheckComplete", 1445 base::StringValue(type_string), 1446 base::StringValue(mode_string), 1447 base::StringValue(pattern_string), 1448 base::FundamentalValue(pattern.IsValid())); 1449} 1450 1451// static 1452std::string ContentSettingsHandler::ContentSettingsTypeToGroupName( 1453 ContentSettingsType type) { 1454 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) { 1455 if (type == kContentSettingsTypeGroupNames[i].type) 1456 return kContentSettingsTypeGroupNames[i].name; 1457 } 1458 1459 NOTREACHED(); 1460 return std::string(); 1461} 1462 1463HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() { 1464 return Profile::FromWebUI(web_ui())->GetHostContentSettingsMap(); 1465} 1466 1467ProtocolHandlerRegistry* ContentSettingsHandler::GetProtocolHandlerRegistry() { 1468 return ProtocolHandlerRegistryFactory::GetForProfile( 1469 Profile::FromWebUI(web_ui())); 1470} 1471 1472HostContentSettingsMap* 1473 ContentSettingsHandler::GetOTRContentSettingsMap() { 1474 Profile* profile = Profile::FromWebUI(web_ui()); 1475 if (profile->HasOffTheRecordProfile()) 1476 return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap(); 1477 return NULL; 1478} 1479 1480void ContentSettingsHandler::RefreshFlashMediaSettings() { 1481 media_settings_.flash_settings_initialized = false; 1482 1483 media_settings_.last_flash_refresh_request_id = 1484 flash_settings_manager_->GetPermissionSettings( 1485 PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC); 1486} 1487 1488void ContentSettingsHandler::OnPepperFlashPrefChanged() { 1489 ShowFlashMediaLink(DEFAULT_SETTING, false); 1490 ShowFlashMediaLink(EXCEPTIONS, false); 1491 1492 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); 1493 if (prefs->GetBoolean(prefs::kPepperFlashSettingsEnabled)) 1494 RefreshFlashMediaSettings(); 1495 else 1496 media_settings_.flash_settings_initialized = false; 1497} 1498 1499void ContentSettingsHandler::OnZoomLevelChanged( 1500 const content::HostZoomMap::ZoomLevelChange& change) { 1501 UpdateZoomLevelsExceptionsView(); 1502} 1503 1504void ContentSettingsHandler::ShowFlashMediaLink(LinkType link_type, bool show) { 1505 bool& show_link = link_type == DEFAULT_SETTING ? 1506 media_settings_.show_flash_default_link : 1507 media_settings_.show_flash_exceptions_link; 1508 if (show_link != show) { 1509 web_ui()->CallJavascriptFunction( 1510 link_type == DEFAULT_SETTING ? 1511 "ContentSettings.showMediaPepperFlashDefaultLink" : 1512 "ContentSettings.showMediaPepperFlashExceptionsLink", 1513 base::FundamentalValue(show)); 1514 show_link = show; 1515 } 1516} 1517 1518void ContentSettingsHandler::UpdateFlashMediaLinksVisibility() { 1519 if (!media_settings_.flash_settings_initialized || 1520 !media_settings_.default_setting_initialized || 1521 !media_settings_.exceptions_initialized) { 1522 return; 1523 } 1524 1525 // Flash won't send us notifications when its settings get changed, which 1526 // means the Flash settings in |media_settings_| may be out-dated, especially 1527 // after we show links to change Flash settings. 1528 // In order to avoid confusion, we won't hide the links once they are showed. 1529 // One exception is that we will hide them when Pepper Flash is disabled 1530 // (handled in OnPepperFlashPrefChanged()). 1531 if (media_settings_.show_flash_default_link && 1532 media_settings_.show_flash_exceptions_link) { 1533 return; 1534 } 1535 1536 if (!media_settings_.show_flash_default_link) { 1537 // If both audio and video capture are disabled by policy, the link 1538 // shouldn't be showed. Flash conforms to the policy in this case because 1539 // it cannot open those devices. We don't have to look at the Flash 1540 // settings. 1541 if (!(media_settings_.policy_disable_audio && 1542 media_settings_.policy_disable_video) && 1543 media_settings_.flash_default_setting != 1544 media_settings_.default_setting) { 1545 ShowFlashMediaLink(DEFAULT_SETTING, true); 1546 } 1547 } 1548 if (!media_settings_.show_flash_exceptions_link) { 1549 // If audio or video capture is disabled by policy, we skip comparison of 1550 // exceptions for audio or video capture, respectively. 1551 if (!PepperFlashContentSettingsUtils::AreMediaExceptionsEqual( 1552 media_settings_.default_setting, 1553 media_settings_.exceptions, 1554 media_settings_.flash_default_setting, 1555 media_settings_.flash_exceptions, 1556 media_settings_.policy_disable_audio, 1557 media_settings_.policy_disable_video)) { 1558 ShowFlashMediaLink(EXCEPTIONS, true); 1559 } 1560 } 1561} 1562 1563void ContentSettingsHandler::UpdateProtectedContentExceptionsButton() { 1564 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); 1565 // Exceptions apply only when the feature is enabled. 1566 bool enable_exceptions = prefs->GetBoolean(prefs::kEnableDRM); 1567 web_ui()->CallJavascriptFunction( 1568 "ContentSettings.enableProtectedContentExceptions", 1569 base::FundamentalValue(enable_exceptions)); 1570} 1571 1572} // namespace options 1573