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.
5 #include "chrome/browser/ui/webui/options/content_settings_handler.h"
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_provider.h"
22 #include "chrome/browser/content_settings/content_settings_utils.h"
23 #include "chrome/browser/content_settings/host_content_settings_map.h"
24 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
25 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
26 #include "chrome/browser/extensions/extension_special_storage_policy.h"
27 #include "chrome/browser/notifications/desktop_notification_profile_util.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/ui/browser_list.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/content_settings.h"
32 #include "chrome/common/content_settings_pattern.h"
33 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
34 #include "chrome/common/pref_names.h"
35 #include "chrome/common/url_constants.h"
36 #include "components/google/core/browser/google_util.h"
37 #include "components/user_prefs/user_prefs.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_contents.h"
43 #include "content/public/browser/web_ui.h"
44 #include "content/public/common/content_switches.h"
45 #include "content/public/common/page_zoom.h"
46 #include "extensions/browser/extension_registry.h"
47 #include "extensions/common/extension_set.h"
48 #include "extensions/common/permissions/api_permission.h"
49 #include "extensions/common/permissions/permissions_data.h"
50 #include "grit/generated_resources.h"
51 #include "grit/locale_settings.h"
52 #include "ui/base/l10n/l10n_util.h"
54 #if defined(OS_CHROMEOS)
55 #include "components/user_manager/user_manager.h"
58 using base::UserMetricsAction;
59 using extensions::APIPermission;
63 struct ContentSettingsTypeNameEntry {
64 ContentSettingsType type;
68 // Maps from a secondary pattern to a setting.
69 typedef std::map<ContentSettingsPattern, ContentSetting>
71 // Maps from a primary pattern/source pair to a OnePatternSettings. All the
72 // mappings in OnePatternSettings share the given primary pattern and source.
73 typedef std::map<std::pair<ContentSettingsPattern, std::string>,
77 // The AppFilter is used in AddExceptionsGrantedByHostedApps() to choose
78 // extensions which should have their extent displayed.
79 typedef bool (*AppFilter)(const extensions::Extension& app,
80 content::BrowserContext* profile);
82 const char kExceptionsLearnMoreUrl[] =
83 "https://support.google.com/chrome/?p=settings_manage_exceptions";
85 const char* kSetting = "setting";
86 const char* kOrigin = "origin";
87 const char* kSource = "source";
88 const char* kAppName = "appName";
89 const char* kAppId = "appId";
90 const char* kEmbeddingOrigin = "embeddingOrigin";
91 const char* kPreferencesSource = "preference";
92 const char* kVideoSetting = "video";
93 const char* kZoom = "zoom";
95 const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = {
96 {CONTENT_SETTINGS_TYPE_COOKIES, "cookies"},
97 {CONTENT_SETTINGS_TYPE_IMAGES, "images"},
98 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, "javascript"},
99 {CONTENT_SETTINGS_TYPE_PLUGINS, "plugins"},
100 {CONTENT_SETTINGS_TYPE_POPUPS, "popups"},
101 {CONTENT_SETTINGS_TYPE_GEOLOCATION, "location"},
102 {CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "notifications"},
103 {CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, "auto-select-certificate"},
104 {CONTENT_SETTINGS_TYPE_FULLSCREEN, "fullscreen"},
105 {CONTENT_SETTINGS_TYPE_MOUSELOCK, "mouselock"},
106 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, "register-protocol-handler"},
107 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, "media-stream"},
108 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, "media-stream-mic"},
109 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, "media-stream-camera"},
110 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, "ppapi-broker"},
111 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, "multiple-automatic-downloads"},
112 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, "midi-sysex"},
113 {CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, "push-messaging"},
114 {CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, "ssl-cert-decisions"},
115 #if defined(OS_CHROMEOS)
116 {CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, "protectedContent"},
120 // A pseudo content type. We use it to display data like a content setting even
121 // though it is not a real content setting.
122 const char* kZoomContentType = "zoomlevels";
124 content::BrowserContext* GetBrowserContext(content::WebUI* web_ui) {
125 return web_ui->GetWebContents()->GetBrowserContext();
128 ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) {
129 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) {
130 if (name == kContentSettingsTypeGroupNames[i].name)
131 return kContentSettingsTypeGroupNames[i].type;
134 NOTREACHED() << name << " is not a recognized content settings type.";
135 return CONTENT_SETTINGS_TYPE_DEFAULT;
138 std::string ContentSettingToString(ContentSetting setting) {
140 case CONTENT_SETTING_ALLOW:
142 case CONTENT_SETTING_ASK:
144 case CONTENT_SETTING_BLOCK:
146 case CONTENT_SETTING_SESSION_ONLY:
148 case CONTENT_SETTING_DEFAULT:
150 case CONTENT_SETTING_NUM_SETTINGS:
154 return std::string();
157 ContentSetting ContentSettingFromString(const std::string& name) {
159 return CONTENT_SETTING_ALLOW;
161 return CONTENT_SETTING_ASK;
163 return CONTENT_SETTING_BLOCK;
164 if (name == "session")
165 return CONTENT_SETTING_SESSION_ONLY;
167 NOTREACHED() << name << " is not a recognized content setting.";
168 return CONTENT_SETTING_DEFAULT;
171 // Create a DictionaryValue* that will act as a data source for a single row
172 // in a HostContentSettingsMap-controlled exceptions table (e.g., cookies).
173 // Ownership of the pointer is passed to the caller.
174 base::DictionaryValue* GetExceptionForPage(
175 const ContentSettingsPattern& pattern,
176 const ContentSettingsPattern& secondary_pattern,
177 const ContentSetting& setting,
178 const std::string& provider_name) {
179 base::DictionaryValue* exception = new base::DictionaryValue();
180 exception->SetString(kOrigin, pattern.ToString());
181 exception->SetString(kEmbeddingOrigin,
182 secondary_pattern == ContentSettingsPattern::Wildcard() ?
184 secondary_pattern.ToString());
185 exception->SetString(kSetting, ContentSettingToString(setting));
186 exception->SetString(kSource, provider_name);
190 // Create a DictionaryValue* that will act as a data source for a single row
191 // in the Geolocation exceptions table. Ownership of the pointer is passed to
193 base::DictionaryValue* GetGeolocationExceptionForPage(
194 const ContentSettingsPattern& origin,
195 const ContentSettingsPattern& embedding_origin,
196 ContentSetting setting) {
197 base::DictionaryValue* exception = new base::DictionaryValue();
198 exception->SetString(kSetting, ContentSettingToString(setting));
199 exception->SetString(kOrigin, origin.ToString());
200 exception->SetString(kEmbeddingOrigin, embedding_origin.ToString());
204 // Create a DictionaryValue* that will act as a data source for a single row
205 // in the desktop notifications exceptions table. Ownership of the pointer is
206 // passed to the caller.
207 base::DictionaryValue* GetNotificationExceptionForPage(
208 const ContentSettingsPattern& pattern,
209 ContentSetting setting,
210 const std::string& provider_name) {
211 base::DictionaryValue* exception = new base::DictionaryValue();
212 exception->SetString(kSetting, ContentSettingToString(setting));
213 exception->SetString(kOrigin, pattern.ToString());
214 exception->SetString(kSource, provider_name);
218 // Returns true whenever the |extension| is hosted and has |permission|.
219 // Must have the AppFilter signature.
220 template <APIPermission::ID permission>
221 bool HostedAppHasPermission(const extensions::Extension& extension,
222 content::BrowserContext* /* context */) {
223 return extension.is_hosted_app() &&
224 extension.permissions_data()->HasAPIPermission(permission);
227 // Add an "Allow"-entry to the list of |exceptions| for a |url_pattern| from
228 // the web extent of a hosted |app|.
229 void AddExceptionForHostedApp(const std::string& url_pattern,
230 const extensions::Extension& app, base::ListValue* exceptions) {
231 base::DictionaryValue* exception = new base::DictionaryValue();
232 exception->SetString(kSetting, ContentSettingToString(CONTENT_SETTING_ALLOW));
233 exception->SetString(kOrigin, url_pattern);
234 exception->SetString(kEmbeddingOrigin, url_pattern);
235 exception->SetString(kSource, "HostedApp");
236 exception->SetString(kAppName, app.name());
237 exception->SetString(kAppId, app.id());
238 exceptions->Append(exception);
241 // Asks the |profile| for hosted apps which have the |permission| set, and
242 // adds their web extent and launch URL to the |exceptions| list.
243 void AddExceptionsGrantedByHostedApps(content::BrowserContext* context,
244 AppFilter app_filter,
245 base::ListValue* exceptions) {
246 const extensions::ExtensionSet& extensions =
247 extensions::ExtensionRegistry::Get(context)->enabled_extensions();
248 for (extensions::ExtensionSet::const_iterator extension = extensions.begin();
249 extension != extensions.end(); ++extension) {
250 if (!app_filter(*extension->get(), context))
253 extensions::URLPatternSet web_extent = (*extension)->web_extent();
254 // Add patterns from web extent.
255 for (extensions::URLPatternSet::const_iterator pattern = web_extent.begin();
256 pattern != web_extent.end(); ++pattern) {
257 std::string url_pattern = pattern->GetAsString();
258 AddExceptionForHostedApp(url_pattern, *extension->get(), exceptions);
260 // Retrieve the launch URL.
262 extensions::AppLaunchInfo::GetLaunchWebURL(extension->get());
263 // Skip adding the launch URL if it is part of the web extent.
264 if (web_extent.MatchesURL(launch_url))
266 AddExceptionForHostedApp(launch_url.spec(), *extension->get(), exceptions);
270 // Sort ZoomLevelChanges by host and scheme
271 // (a.com < http://a.com < https://a.com < b.com).
272 bool HostZoomSort(const content::HostZoomMap::ZoomLevelChange& a,
273 const content::HostZoomMap::ZoomLevelChange& b) {
274 return a.host == b.host ? a.scheme < b.scheme : a.host < b.host;
281 ContentSettingsHandler::MediaSettingsInfo::MediaSettingsInfo()
282 : flash_default_setting(CONTENT_SETTING_DEFAULT),
283 flash_settings_initialized(false),
284 last_flash_refresh_request_id(0),
285 show_flash_default_link(false),
286 show_flash_exceptions_link(false),
287 default_setting(CONTENT_SETTING_DEFAULT),
288 policy_disable_audio(false),
289 policy_disable_video(false),
290 default_setting_initialized(false),
291 exceptions_initialized(false) {
294 ContentSettingsHandler::MediaSettingsInfo::~MediaSettingsInfo() {
297 ContentSettingsHandler::ContentSettingsHandler() {
300 ContentSettingsHandler::~ContentSettingsHandler() {
303 void ContentSettingsHandler::GetLocalizedValues(
304 base::DictionaryValue* localized_strings) {
305 DCHECK(localized_strings);
307 static OptionsStringResource resources[] = {
308 { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON },
309 { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON },
310 { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON },
311 { "askException", IDS_EXCEPTIONS_ASK_BUTTON },
312 { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL },
313 { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS },
314 { "manageExceptions", IDS_EXCEPTIONS_MANAGE },
315 { "manage_handlers", IDS_HANDLERS_MANAGE },
316 { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER },
317 { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER },
318 { "exceptionZoomHeader", IDS_EXCEPTIONS_ZOOM_HEADER },
319 { "embeddedOnHost", IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST },
321 { "cookies_tab_label", IDS_COOKIES_TAB_LABEL },
322 { "cookies_header", IDS_COOKIES_HEADER },
323 { "cookies_allow", IDS_COOKIES_ALLOW_RADIO },
324 { "cookies_block", IDS_COOKIES_BLOCK_RADIO },
325 { "cookies_session_only", IDS_COOKIES_SESSION_ONLY_RADIO },
326 { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX },
327 { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX },
328 { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX },
329 { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON },
330 { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS },
331 { "flash_storage_url", IDS_FLASH_STORAGE_URL },
332 #if defined(ENABLE_GOOGLE_NOW)
333 { "googleGeolocationAccessEnable",
334 IDS_GEOLOCATION_GOOGLE_ACCESS_ENABLE_CHKBOX },
337 { "images_tab_label", IDS_IMAGES_TAB_LABEL },
338 { "images_header", IDS_IMAGES_HEADER },
339 { "images_allow", IDS_IMAGES_LOAD_RADIO },
340 { "images_block", IDS_IMAGES_NOLOAD_RADIO },
341 // JavaScript filter.
342 { "javascript_tab_label", IDS_JAVASCRIPT_TAB_LABEL },
343 { "javascript_header", IDS_JAVASCRIPT_HEADER },
344 { "javascript_allow", IDS_JS_ALLOW_RADIO },
345 { "javascript_block", IDS_JS_DONOTALLOW_RADIO },
347 { "plugins_tab_label", IDS_PLUGIN_TAB_LABEL },
348 { "plugins_header", IDS_PLUGIN_HEADER },
349 { "plugins_ask", IDS_PLUGIN_ASK_RADIO },
350 { "plugins_allow", IDS_PLUGIN_LOAD_RADIO },
351 { "plugins_block", IDS_PLUGIN_NOLOAD_RADIO },
352 { "disableIndividualPlugins", IDS_PLUGIN_SELECTIVE_DISABLE },
354 { "popups_tab_label", IDS_POPUP_TAB_LABEL },
355 { "popups_header", IDS_POPUP_HEADER },
356 { "popups_allow", IDS_POPUP_ALLOW_RADIO },
357 { "popups_block", IDS_POPUP_BLOCK_RADIO },
359 { "location_tab_label", IDS_GEOLOCATION_TAB_LABEL },
360 { "location_header", IDS_GEOLOCATION_HEADER },
361 { "location_allow", IDS_GEOLOCATION_ALLOW_RADIO },
362 { "location_ask", IDS_GEOLOCATION_ASK_RADIO },
363 { "location_block", IDS_GEOLOCATION_BLOCK_RADIO },
364 { "set_by", IDS_GEOLOCATION_SET_BY_HOVER },
365 // Notifications filter.
366 { "notifications_tab_label", IDS_NOTIFICATIONS_TAB_LABEL },
367 { "notifications_header", IDS_NOTIFICATIONS_HEADER },
368 { "notifications_allow", IDS_NOTIFICATIONS_ALLOW_RADIO },
369 { "notifications_ask", IDS_NOTIFICATIONS_ASK_RADIO },
370 { "notifications_block", IDS_NOTIFICATIONS_BLOCK_RADIO },
371 // Fullscreen filter.
372 { "fullscreen_tab_label", IDS_FULLSCREEN_TAB_LABEL },
373 { "fullscreen_header", IDS_FULLSCREEN_HEADER },
374 // Mouse Lock filter.
375 { "mouselock_tab_label", IDS_MOUSE_LOCK_TAB_LABEL },
376 { "mouselock_header", IDS_MOUSE_LOCK_HEADER },
377 { "mouselock_allow", IDS_MOUSE_LOCK_ALLOW_RADIO },
378 { "mouselock_ask", IDS_MOUSE_LOCK_ASK_RADIO },
379 { "mouselock_block", IDS_MOUSE_LOCK_BLOCK_RADIO },
380 #if defined(OS_CHROMEOS) || defined(OS_WIN)
381 // Protected Content filter
382 { "protectedContentTabLabel", IDS_PROTECTED_CONTENT_TAB_LABEL },
383 { "protectedContentInfo", IDS_PROTECTED_CONTENT_INFO },
384 { "protectedContentEnable", IDS_PROTECTED_CONTENT_ENABLE },
385 { "protectedContent_header", IDS_PROTECTED_CONTENT_HEADER },
386 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
387 // Media stream capture device filter.
388 { "mediaStreamTabLabel", IDS_MEDIA_STREAM_TAB_LABEL },
389 { "media-stream_header", IDS_MEDIA_STREAM_HEADER },
390 { "mediaStreamAsk", IDS_MEDIA_STREAM_ASK_RADIO },
391 { "mediaStreamBlock", IDS_MEDIA_STREAM_BLOCK_RADIO },
392 { "mediaStreamAudioAsk", IDS_MEDIA_STREAM_ASK_AUDIO_ONLY_RADIO },
393 { "mediaStreamAudioBlock", IDS_MEDIA_STREAM_BLOCK_AUDIO_ONLY_RADIO },
394 { "mediaStreamVideoAsk", IDS_MEDIA_STREAM_ASK_VIDEO_ONLY_RADIO },
395 { "mediaStreamVideoBlock", IDS_MEDIA_STREAM_BLOCK_VIDEO_ONLY_RADIO },
396 { "mediaStreamBubbleAudio", IDS_MEDIA_STREAM_AUDIO_MANAGED },
397 { "mediaStreamBubbleVideo", IDS_MEDIA_STREAM_VIDEO_MANAGED },
398 { "mediaAudioExceptionHeader", IDS_MEDIA_AUDIO_EXCEPTION_HEADER },
399 { "mediaVideoExceptionHeader", IDS_MEDIA_VIDEO_EXCEPTION_HEADER },
400 { "mediaPepperFlashDefaultDivergedLabel",
401 IDS_MEDIA_PEPPER_FLASH_DEFAULT_DIVERGED_LABEL },
402 { "mediaPepperFlashExceptionsDivergedLabel",
403 IDS_MEDIA_PEPPER_FLASH_EXCEPTIONS_DIVERGED_LABEL },
404 { "mediaPepperFlashChangeLink", IDS_MEDIA_PEPPER_FLASH_CHANGE_LINK },
405 { "mediaPepperFlashGlobalPrivacyURL", IDS_FLASH_GLOBAL_PRIVACY_URL },
406 { "mediaPepperFlashWebsitePrivacyURL", IDS_FLASH_WEBSITE_PRIVACY_URL },
407 // PPAPI broker filter.
408 { "ppapi-broker_header", IDS_PPAPI_BROKER_HEADER },
409 { "ppapiBrokerTabLabel", IDS_PPAPI_BROKER_TAB_LABEL },
410 { "ppapi_broker_allow", IDS_PPAPI_BROKER_ALLOW_RADIO },
411 { "ppapi_broker_ask", IDS_PPAPI_BROKER_ASK_RADIO },
412 { "ppapi_broker_block", IDS_PPAPI_BROKER_BLOCK_RADIO },
413 // Multiple automatic downloads
414 { "multiple-automatic-downloads_header",
415 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL },
416 { "multiple-automatic-downloads_allow",
417 IDS_AUTOMATIC_DOWNLOADS_ALLOW_RADIO },
418 { "multiple-automatic-downloads_ask",
419 IDS_AUTOMATIC_DOWNLOADS_ASK_RADIO },
420 { "multiple-automatic-downloads_block",
421 IDS_AUTOMATIC_DOWNLOADS_BLOCK_RADIO },
422 // MIDI system exclusive messages
423 { "midi-sysex_header", IDS_MIDI_SYSEX_TAB_LABEL },
424 { "midiSysExAllow", IDS_MIDI_SYSEX_ALLOW_RADIO },
425 { "midiSysExAsk", IDS_MIDI_SYSEX_ASK_RADIO },
426 { "midiSysExBlock", IDS_MIDI_SYSEX_BLOCK_RADIO },
427 // Push messaging strings
428 { "push-messaging_header", IDS_PUSH_MESSAGES_TAB_LABEL },
429 { "pushMessagingAllow", IDS_PUSH_MESSSAGING_ALLOW_RADIO },
430 { "pushMessagingAsk", IDS_PUSH_MESSSAGING_ASK_RADIO },
431 { "pushMessagingBlock", IDS_PUSH_MESSSAGING_BLOCK_RADIO },
432 { "zoomlevels_header", IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL },
433 { "zoomLevelsManage", IDS_ZOOMLEVELS_MANAGE_BUTTON },
436 RegisterStrings(localized_strings, resources, arraysize(resources));
437 RegisterTitle(localized_strings, "contentSettingsPage",
438 IDS_CONTENT_SETTINGS_TITLE);
440 // Register titles for each of the individual settings whose exception
441 // dialogs will be processed by |ContentSettingsHandler|.
442 RegisterTitle(localized_strings, "cookies",
443 IDS_COOKIES_TAB_LABEL);
444 RegisterTitle(localized_strings, "images",
445 IDS_IMAGES_TAB_LABEL);
446 RegisterTitle(localized_strings, "javascript",
447 IDS_JAVASCRIPT_TAB_LABEL);
448 RegisterTitle(localized_strings, "plugins",
449 IDS_PLUGIN_TAB_LABEL);
450 RegisterTitle(localized_strings, "popups",
451 IDS_POPUP_TAB_LABEL);
452 RegisterTitle(localized_strings, "location",
453 IDS_GEOLOCATION_TAB_LABEL);
454 RegisterTitle(localized_strings, "notifications",
455 IDS_NOTIFICATIONS_TAB_LABEL);
456 RegisterTitle(localized_strings, "fullscreen",
457 IDS_FULLSCREEN_TAB_LABEL);
458 RegisterTitle(localized_strings, "mouselock",
459 IDS_MOUSE_LOCK_TAB_LABEL);
460 #if defined(OS_CHROMEOS)
461 RegisterTitle(localized_strings, "protectedContent",
462 IDS_PROTECTED_CONTENT_TAB_LABEL);
464 RegisterTitle(localized_strings, "media-stream",
465 IDS_MEDIA_STREAM_TAB_LABEL);
466 RegisterTitle(localized_strings, "ppapi-broker",
467 IDS_PPAPI_BROKER_TAB_LABEL);
468 RegisterTitle(localized_strings, "multiple-automatic-downloads",
469 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL);
470 RegisterTitle(localized_strings, "midi-sysex",
471 IDS_MIDI_SYSEX_TAB_LABEL);
472 RegisterTitle(localized_strings, "zoomlevels",
473 IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL);
475 localized_strings->SetString("exceptionsLearnMoreUrl",
476 kExceptionsLearnMoreUrl);
479 void ContentSettingsHandler::InitializeHandler() {
480 notification_registrar_.Add(
481 this, chrome::NOTIFICATION_PROFILE_CREATED,
482 content::NotificationService::AllSources());
483 notification_registrar_.Add(
484 this, chrome::NOTIFICATION_PROFILE_DESTROYED,
485 content::NotificationService::AllSources());
487 notification_registrar_.Add(
488 this, chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED,
489 content::NotificationService::AllSources());
490 notification_registrar_.Add(
491 this, chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
492 content::NotificationService::AllSources());
493 content::BrowserContext* context = GetBrowserContext(web_ui());
494 notification_registrar_.Add(
495 this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
496 content::Source<content::BrowserContext>(context));
498 PrefService* prefs = user_prefs::UserPrefs::Get(context);
499 pref_change_registrar_.Init(prefs);
500 pref_change_registrar_.Add(
501 prefs::kPepperFlashSettingsEnabled,
502 base::Bind(&ContentSettingsHandler::OnPepperFlashPrefChanged,
503 base::Unretained(this)));
504 pref_change_registrar_.Add(
505 prefs::kAudioCaptureAllowed,
506 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView,
507 base::Unretained(this)));
508 pref_change_registrar_.Add(
509 prefs::kVideoCaptureAllowed,
510 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView,
511 base::Unretained(this)));
512 pref_change_registrar_.Add(
515 &ContentSettingsHandler::UpdateProtectedContentExceptionsButton,
516 base::Unretained(this)));
518 content::HostZoomMap* host_zoom_map =
519 content::HostZoomMap::GetForBrowserContext(context);
520 host_zoom_map_subscription_ =
521 host_zoom_map->AddZoomLevelChangedCallback(
522 base::Bind(&ContentSettingsHandler::OnZoomLevelChanged,
523 base::Unretained(this)));
525 flash_settings_manager_.reset(new PepperFlashSettingsManager(this, context));
528 void ContentSettingsHandler::InitializePage() {
529 media_settings_ = MediaSettingsInfo();
530 RefreshFlashMediaSettings();
532 UpdateHandlersEnabledRadios();
533 UpdateAllExceptionsViewsFromModel();
534 UpdateProtectedContentExceptionsButton();
537 void ContentSettingsHandler::Observe(
539 const content::NotificationSource& source,
540 const content::NotificationDetails& details) {
542 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
543 if (content::Source<Profile>(source).ptr()->IsOffTheRecord()) {
544 web_ui()->CallJavascriptFunction(
545 "ContentSettingsExceptionsArea.OTRProfileDestroyed");
550 case chrome::NOTIFICATION_PROFILE_CREATED: {
551 if (content::Source<Profile>(source).ptr()->IsOffTheRecord())
552 UpdateAllOTRExceptionsViewsFromModel();
556 case chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED: {
557 // Filter out notifications from other profiles.
558 HostContentSettingsMap* map =
559 content::Source<HostContentSettingsMap>(source).ptr();
560 if (map != GetContentSettingsMap() &&
561 map != GetOTRContentSettingsMap())
564 const ContentSettingsDetails* settings_details =
565 content::Details<const ContentSettingsDetails>(details).ptr();
567 // TODO(estade): we pretend update_all() is always true.
568 if (settings_details->update_all_types())
569 UpdateAllExceptionsViewsFromModel();
571 UpdateExceptionsViewFromModel(settings_details->type());
575 case chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED: {
576 UpdateNotificationExceptionsView();
580 case chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED: {
581 UpdateHandlersEnabledRadios();
587 void ContentSettingsHandler::OnGetPermissionSettingsCompleted(
590 PP_Flash_BrowserOperations_Permission default_permission,
591 const ppapi::FlashSiteSettings& sites) {
592 if (success && request_id == media_settings_.last_flash_refresh_request_id) {
593 media_settings_.flash_settings_initialized = true;
594 media_settings_.flash_default_setting =
595 PepperFlashContentSettingsUtils::FlashPermissionToContentSetting(
597 PepperFlashContentSettingsUtils::FlashSiteSettingsToMediaExceptions(
598 sites, &media_settings_.flash_exceptions);
599 PepperFlashContentSettingsUtils::SortMediaExceptions(
600 &media_settings_.flash_exceptions);
602 UpdateFlashMediaLinksVisibility();
606 void ContentSettingsHandler::UpdateSettingDefaultFromModel(
607 ContentSettingsType type) {
608 base::DictionaryValue filter_settings;
609 std::string provider_id;
610 filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value",
611 GetSettingDefaultFromModel(type, &provider_id));
612 filter_settings.SetString(
613 ContentSettingsTypeToGroupName(type) + ".managedBy", provider_id);
615 web_ui()->CallJavascriptFunction(
616 "ContentSettings.setContentFilterSettingsValue", filter_settings);
619 void ContentSettingsHandler::UpdateMediaSettingsView() {
620 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
621 bool audio_disabled = !prefs->GetBoolean(prefs::kAudioCaptureAllowed) &&
622 prefs->IsManagedPreference(prefs::kAudioCaptureAllowed);
623 bool video_disabled = !prefs->GetBoolean(prefs::kVideoCaptureAllowed) &&
624 prefs->IsManagedPreference(prefs::kVideoCaptureAllowed);
626 media_settings_.policy_disable_audio = audio_disabled;
627 media_settings_.policy_disable_video = video_disabled;
628 media_settings_.default_setting =
629 GetContentSettingsMap()->GetDefaultContentSetting(
630 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL);
631 media_settings_.default_setting_initialized = true;
632 UpdateFlashMediaLinksVisibility();
634 base::DictionaryValue media_ui_settings;
635 media_ui_settings.SetBoolean("cameraDisabled", video_disabled);
636 media_ui_settings.SetBoolean("micDisabled", audio_disabled);
638 // In case only video is enabled change the text appropriately.
639 if (audio_disabled && !video_disabled) {
640 media_ui_settings.SetString("askText", "mediaStreamVideoAsk");
641 media_ui_settings.SetString("blockText", "mediaStreamVideoBlock");
642 media_ui_settings.SetBoolean("showBubble", true);
643 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleAudio");
645 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
650 // In case only audio is enabled change the text appropriately.
651 if (video_disabled && !audio_disabled) {
652 base::DictionaryValue media_ui_settings;
653 media_ui_settings.SetString("askText", "mediaStreamAudioAsk");
654 media_ui_settings.SetString("blockText", "mediaStreamAudioBlock");
655 media_ui_settings.SetBoolean("showBubble", true);
656 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleVideo");
658 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
663 if (audio_disabled && video_disabled) {
664 // Fake policy controlled default because the user can not change anything
665 // until both audio and video are blocked.
666 base::DictionaryValue filter_settings;
667 std::string group_name =
668 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
669 filter_settings.SetString(group_name + ".value",
670 ContentSettingToString(CONTENT_SETTING_BLOCK));
671 filter_settings.SetString(group_name + ".managedBy", "policy");
672 web_ui()->CallJavascriptFunction(
673 "ContentSettings.setContentFilterSettingsValue", filter_settings);
676 media_ui_settings.SetString("askText", "mediaStreamAsk");
677 media_ui_settings.SetString("blockText", "mediaStreamBlock");
678 media_ui_settings.SetBoolean("showBubble", false);
679 media_ui_settings.SetString("bubbleText", std::string());
681 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
685 std::string ContentSettingsHandler::GetSettingDefaultFromModel(
686 ContentSettingsType type, std::string* provider_id) {
687 Profile* profile = Profile::FromWebUI(web_ui());
688 ContentSetting default_setting;
690 profile->GetHostContentSettingsMap()->GetDefaultContentSetting(
693 return ContentSettingToString(default_setting);
696 void ContentSettingsHandler::UpdateHandlersEnabledRadios() {
697 base::FundamentalValue handlers_enabled(
698 GetProtocolHandlerRegistry()->enabled());
700 web_ui()->CallJavascriptFunction(
701 "ContentSettings.updateHandlersEnabledRadios",
705 void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() {
706 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
707 type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
708 UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
710 // Zoom levels are not actually a content type so we need to handle them
712 UpdateZoomLevelsExceptionsView();
715 void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() {
716 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
717 type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
718 UpdateOTRExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
722 void ContentSettingsHandler::UpdateExceptionsViewFromModel(
723 ContentSettingsType type) {
725 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
726 UpdateGeolocationExceptionsView();
728 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
729 UpdateNotificationExceptionsView();
731 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
732 UpdateMediaSettingsView();
734 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
735 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
736 UpdateMediaExceptionsView();
738 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
739 // We don't yet support exceptions for mixed scripting.
741 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
742 // The content settings type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE
743 // is supposed to be set by policy only. Hence there is no user facing UI
744 // for this content type and we skip it here.
746 case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS:
747 // The RPH settings are retrieved separately.
749 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
750 UpdateMIDISysExExceptionsView();
752 case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS:
753 // The content settings type CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS is
754 // supposed to be set by flags and field trials only, thus there is no
755 // user facing UI for this content type and we skip it here.
758 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
762 UpdateExceptionsViewFromHostContentSettingsMap(type);
767 void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel(
768 ContentSettingsType type) {
770 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
771 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
772 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
773 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
775 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
777 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
778 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
779 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
780 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
781 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
782 case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS:
785 UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
790 // TODO(estade): merge with GetExceptionsFromHostContentSettingsMap.
791 void ContentSettingsHandler::UpdateGeolocationExceptionsView() {
792 Profile* profile = Profile::FromWebUI(web_ui());
793 HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
795 ContentSettingsForOneType all_settings;
796 map->GetSettingsForOneType(
797 CONTENT_SETTINGS_TYPE_GEOLOCATION,
801 // Group geolocation settings by primary_pattern.
802 AllPatternsSettings all_patterns_settings;
803 for (ContentSettingsForOneType::iterator i = all_settings.begin();
804 i != all_settings.end(); ++i) {
805 // Don't add default settings.
806 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
807 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
808 i->source != kPreferencesSource) {
811 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
812 [i->secondary_pattern] = i->setting;
815 base::ListValue exceptions;
816 AddExceptionsGrantedByHostedApps(
818 HostedAppHasPermission<APIPermission::kGeolocation>,
821 for (AllPatternsSettings::iterator i = all_patterns_settings.begin();
822 i != all_patterns_settings.end(); ++i) {
823 const ContentSettingsPattern& primary_pattern = i->first.first;
824 const OnePatternSettings& one_settings = i->second;
826 OnePatternSettings::const_iterator parent =
827 one_settings.find(primary_pattern);
829 // Add the "parent" entry for the non-embedded setting.
830 ContentSetting parent_setting =
831 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
832 exceptions.Append(GetGeolocationExceptionForPage(primary_pattern,
836 // Add the "children" for any embedded settings.
837 for (OnePatternSettings::const_iterator j = one_settings.begin();
838 j != one_settings.end();
840 // Skip the non-embedded setting which we already added above.
844 exceptions.Append(GetGeolocationExceptionForPage(
845 primary_pattern, j->first, j->second));
849 base::StringValue type_string(
850 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION));
851 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
852 type_string, exceptions);
854 // This is mainly here to keep this function ideologically parallel to
855 // UpdateExceptionsViewFromHostContentSettingsMap().
856 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION);
859 void ContentSettingsHandler::UpdateNotificationExceptionsView() {
860 Profile* profile = Profile::FromWebUI(web_ui());
861 ContentSettingsForOneType settings;
862 DesktopNotificationProfileUtil::GetNotificationsSettings(profile, &settings);
864 base::ListValue exceptions;
865 AddExceptionsGrantedByHostedApps(
867 HostedAppHasPermission<APIPermission::kNotifications>,
870 for (ContentSettingsForOneType::const_iterator i =
874 // Don't add default settings.
875 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
876 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
877 i->source != kPreferencesSource) {
882 GetNotificationExceptionForPage(i->primary_pattern, i->setting,
886 base::StringValue type_string(
887 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
888 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
889 type_string, exceptions);
891 // This is mainly here to keep this function ideologically parallel to
892 // UpdateExceptionsViewFromHostContentSettingsMap().
893 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
896 void ContentSettingsHandler::UpdateMediaExceptionsView() {
897 base::ListValue media_exceptions;
898 GetExceptionsFromHostContentSettingsMap(
899 GetContentSettingsMap(),
900 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
903 base::ListValue video_exceptions;
904 GetExceptionsFromHostContentSettingsMap(
905 GetContentSettingsMap(),
906 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
909 // Merge the |video_exceptions| list to |media_exceptions| list.
910 std::map<std::string, base::DictionaryValue*> entries_map;
911 for (base::ListValue::const_iterator media_entry(media_exceptions.begin());
912 media_entry != media_exceptions.end(); ++media_entry) {
913 base::DictionaryValue* media_dict = NULL;
914 if (!(*media_entry)->GetAsDictionary(&media_dict))
917 media_dict->SetString(kVideoSetting,
918 ContentSettingToString(CONTENT_SETTING_ASK));
920 std::string media_origin;
921 media_dict->GetString(kOrigin, &media_origin);
922 entries_map[media_origin] = media_dict;
925 for (base::ListValue::iterator video_entry = video_exceptions.begin();
926 video_entry != video_exceptions.end(); ++video_entry) {
927 base::DictionaryValue* video_dict = NULL;
928 if (!(*video_entry)->GetAsDictionary(&video_dict))
931 std::string video_origin;
932 std::string video_setting;
933 video_dict->GetString(kOrigin, &video_origin);
934 video_dict->GetString(kSetting, &video_setting);
936 std::map<std::string, base::DictionaryValue*>::iterator iter =
937 entries_map.find(video_origin);
938 if (iter == entries_map.end()) {
939 base::DictionaryValue* exception = new base::DictionaryValue();
940 exception->SetString(kOrigin, video_origin);
941 exception->SetString(kSetting,
942 ContentSettingToString(CONTENT_SETTING_ASK));
943 exception->SetString(kVideoSetting, video_setting);
944 exception->SetString(kSource, kPreferencesSource);
946 // Append the new entry to the list and map.
947 media_exceptions.Append(exception);
948 entries_map[video_origin] = exception;
950 // Modify the existing entry.
951 iter->second->SetString(kVideoSetting, video_setting);
955 media_settings_.exceptions.clear();
956 for (base::ListValue::const_iterator media_entry = media_exceptions.begin();
957 media_entry != media_exceptions.end(); ++media_entry) {
958 base::DictionaryValue* media_dict = NULL;
959 bool result = (*media_entry)->GetAsDictionary(&media_dict);
963 std::string audio_setting;
964 std::string video_setting;
965 media_dict->GetString(kOrigin, &origin);
966 media_dict->GetString(kSetting, &audio_setting);
967 media_dict->GetString(kVideoSetting, &video_setting);
968 media_settings_.exceptions.push_back(MediaException(
969 ContentSettingsPattern::FromString(origin),
970 ContentSettingFromString(audio_setting),
971 ContentSettingFromString(video_setting)));
973 PepperFlashContentSettingsUtils::SortMediaExceptions(
974 &media_settings_.exceptions);
975 media_settings_.exceptions_initialized = true;
976 UpdateFlashMediaLinksVisibility();
978 base::StringValue type_string(
979 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM));
980 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
981 type_string, media_exceptions);
983 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
986 void ContentSettingsHandler::UpdateMIDISysExExceptionsView() {
987 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebMIDI)) {
988 web_ui()->CallJavascriptFunction(
989 "ContentSettings.showExperimentalWebMIDISettings",
990 base::FundamentalValue(true));
993 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
994 UpdateExceptionsViewFromHostContentSettingsMap(
995 CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
998 void ContentSettingsHandler::UpdateZoomLevelsExceptionsView() {
999 base::ListValue zoom_levels_exceptions;
1001 content::HostZoomMap* host_zoom_map =
1002 content::HostZoomMap::GetForBrowserContext(GetBrowserContext(web_ui()));
1003 content::HostZoomMap::ZoomLevelVector zoom_levels(
1004 host_zoom_map->GetAllZoomLevels());
1005 std::sort(zoom_levels.begin(), zoom_levels.end(), HostZoomSort);
1007 for (content::HostZoomMap::ZoomLevelVector::const_iterator i =
1008 zoom_levels.begin();
1009 i != zoom_levels.end();
1011 scoped_ptr<base::DictionaryValue> exception(new base::DictionaryValue);
1013 case content::HostZoomMap::ZOOM_CHANGED_FOR_HOST:
1014 exception->SetString(kOrigin, i->host);
1016 case content::HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST:
1017 // These are not stored in preferences and get cleared on next browser
1018 // start. Therefore, we don't care for them.
1020 case content::HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM:
1023 exception->SetString(kSetting,
1024 ContentSettingToString(CONTENT_SETTING_DEFAULT));
1026 // Calculate the zoom percent from the factor. Round up to the nearest whole
1028 int zoom_percent = static_cast<int>(
1029 content::ZoomLevelToZoomFactor(i->zoom_level) * 100 + 0.5);
1030 exception->SetString(
1032 l10n_util::GetStringFUTF16(IDS_ZOOM_PERCENT,
1033 base::IntToString16(zoom_percent)));
1034 exception->SetString(kSource, kPreferencesSource);
1035 // Append the new entry to the list and map.
1036 zoom_levels_exceptions.Append(exception.release());
1039 base::StringValue type_string(kZoomContentType);
1040 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
1041 type_string, zoom_levels_exceptions);
1044 void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap(
1045 ContentSettingsType type) {
1046 base::ListValue exceptions;
1047 GetExceptionsFromHostContentSettingsMap(
1048 GetContentSettingsMap(), type, &exceptions);
1049 base::StringValue type_string(ContentSettingsTypeToGroupName(type));
1050 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", type_string,
1053 UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
1055 // TODO(koz): The default for fullscreen is always 'ask'.
1056 // http://crbug.com/104683
1057 if (type == CONTENT_SETTINGS_TYPE_FULLSCREEN)
1060 #if defined(OS_CHROMEOS)
1061 // Also the default for protected contents is managed in another place.
1062 if (type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER)
1066 // The default may also have changed (we won't get a separate notification).
1067 // If it hasn't changed, this call will be harmless.
1068 UpdateSettingDefaultFromModel(type);
1071 void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap(
1072 ContentSettingsType type) {
1073 const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap();
1074 if (!otr_settings_map)
1076 base::ListValue exceptions;
1077 GetExceptionsFromHostContentSettingsMap(otr_settings_map, type, &exceptions);
1078 base::StringValue type_string(ContentSettingsTypeToGroupName(type));
1079 web_ui()->CallJavascriptFunction("ContentSettings.setOTRExceptions",
1080 type_string, exceptions);
1083 void ContentSettingsHandler::GetExceptionsFromHostContentSettingsMap(
1084 const HostContentSettingsMap* map,
1085 ContentSettingsType type,
1086 base::ListValue* exceptions) {
1087 ContentSettingsForOneType entries;
1088 map->GetSettingsForOneType(type, std::string(), &entries);
1089 // Group settings by primary_pattern.
1090 AllPatternsSettings all_patterns_settings;
1091 for (ContentSettingsForOneType::iterator i = entries.begin();
1092 i != entries.end(); ++i) {
1093 // Don't add default settings.
1094 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
1095 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
1096 i->source != kPreferencesSource) {
1100 // Off-the-record HostContentSettingsMap contains incognito content settings
1101 // as well as normal content settings. Here, we use the incongnito settings
1103 if (map->is_off_the_record() && !i->incognito)
1106 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
1107 [i->secondary_pattern] = i->setting;
1110 // Keep the exceptions sorted by provider so they will be displayed in
1111 // precedence order.
1112 std::vector<std::vector<base::Value*> > all_provider_exceptions;
1113 all_provider_exceptions.resize(HostContentSettingsMap::NUM_PROVIDER_TYPES);
1115 for (AllPatternsSettings::iterator i = all_patterns_settings.begin();
1116 i != all_patterns_settings.end();
1118 const ContentSettingsPattern& primary_pattern = i->first.first;
1119 const OnePatternSettings& one_settings = i->second;
1121 // The "parent" entry either has an identical primary and secondary pattern,
1122 // or has a wildcard secondary. The two cases are indistinguishable in the
1124 OnePatternSettings::const_iterator parent =
1125 one_settings.find(primary_pattern);
1126 if (parent == one_settings.end())
1127 parent = one_settings.find(ContentSettingsPattern::Wildcard());
1129 const std::string& source = i->first.second;
1130 std::vector<base::Value*>* this_provider_exceptions =
1131 &all_provider_exceptions.at(
1132 HostContentSettingsMap::GetProviderTypeFromSource(source));
1134 // Add the "parent" entry for the non-embedded setting.
1135 ContentSetting parent_setting =
1136 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
1137 const ContentSettingsPattern& secondary_pattern =
1138 parent == one_settings.end() ? primary_pattern : parent->first;
1139 this_provider_exceptions->push_back(GetExceptionForPage(primary_pattern,
1144 // Add the "children" for any embedded settings.
1145 for (OnePatternSettings::const_iterator j = one_settings.begin();
1146 j != one_settings.end(); ++j) {
1147 // Skip the non-embedded setting which we already added above.
1151 ContentSetting content_setting = j->second;
1152 this_provider_exceptions->push_back(GetExceptionForPage(
1160 for (size_t i = 0; i < all_provider_exceptions.size(); ++i) {
1161 for (size_t j = 0; j < all_provider_exceptions[i].size(); ++j) {
1162 exceptions->Append(all_provider_exceptions[i][j]);
1167 void ContentSettingsHandler::RemoveNotificationException(
1168 const base::ListValue* args) {
1169 Profile* profile = Profile::FromWebUI(web_ui());
1172 std::string setting;
1173 bool rv = args->GetString(1, &origin);
1175 rv = args->GetString(2, &setting);
1177 ContentSetting content_setting = ContentSettingFromString(setting);
1179 DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
1180 content_setting == CONTENT_SETTING_BLOCK);
1181 DesktopNotificationProfileUtil::ClearSetting(profile,
1182 ContentSettingsPattern::FromString(origin));
1185 void ContentSettingsHandler::RemoveMediaException(const base::ListValue* args) {
1187 bool rv = args->GetString(1, &mode);
1190 std::string pattern;
1191 rv = args->GetString(2, &pattern);
1194 HostContentSettingsMap* settings_map =
1195 mode == "normal" ? GetContentSettingsMap() :
1196 GetOTRContentSettingsMap();
1198 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1199 ContentSettingsPattern::Wildcard(),
1200 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
1203 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1204 ContentSettingsPattern::Wildcard(),
1205 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
1211 void ContentSettingsHandler::RemoveExceptionFromHostContentSettingsMap(
1212 const base::ListValue* args,
1213 ContentSettingsType type) {
1215 bool rv = args->GetString(1, &mode);
1218 std::string pattern;
1219 rv = args->GetString(2, &pattern);
1222 // The fourth argument to this handler is optional.
1223 std::string secondary_pattern;
1224 if (args->GetSize() >= 4U) {
1225 rv = args->GetString(3, &secondary_pattern);
1229 HostContentSettingsMap* settings_map =
1230 mode == "normal" ? GetContentSettingsMap() :
1231 GetOTRContentSettingsMap();
1233 settings_map->SetWebsiteSetting(
1234 ContentSettingsPattern::FromString(pattern),
1235 secondary_pattern.empty() ?
1236 ContentSettingsPattern::Wildcard() :
1237 ContentSettingsPattern::FromString(secondary_pattern),
1244 void ContentSettingsHandler::RemoveZoomLevelException(
1245 const base::ListValue* args) {
1247 bool rv = args->GetString(1, &mode);
1250 std::string pattern;
1251 rv = args->GetString(2, &pattern);
1254 content::HostZoomMap* host_zoom_map =
1255 content::HostZoomMap::GetForBrowserContext(GetBrowserContext(web_ui()));
1256 double default_level = host_zoom_map->GetDefaultZoomLevel();
1257 host_zoom_map->SetZoomLevelForHost(pattern, default_level);
1260 void ContentSettingsHandler::RegisterMessages() {
1261 web_ui()->RegisterMessageCallback("setContentFilter",
1262 base::Bind(&ContentSettingsHandler::SetContentFilter,
1263 base::Unretained(this)));
1264 web_ui()->RegisterMessageCallback("removeException",
1265 base::Bind(&ContentSettingsHandler::RemoveException,
1266 base::Unretained(this)));
1267 web_ui()->RegisterMessageCallback("setException",
1268 base::Bind(&ContentSettingsHandler::SetException,
1269 base::Unretained(this)));
1270 web_ui()->RegisterMessageCallback("checkExceptionPatternValidity",
1271 base::Bind(&ContentSettingsHandler::CheckExceptionPatternValidity,
1272 base::Unretained(this)));
1275 void ContentSettingsHandler::ApplyWhitelist(ContentSettingsType content_type,
1276 ContentSetting default_setting) {
1277 HostContentSettingsMap* map = GetContentSettingsMap();
1278 if (content_type != CONTENT_SETTINGS_TYPE_PLUGINS)
1280 const int kDefaultWhitelistVersion = 1;
1281 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
1282 int version = prefs->GetInteger(
1283 prefs::kContentSettingsDefaultWhitelistVersion);
1284 if (version >= kDefaultWhitelistVersion)
1286 ContentSetting old_setting =
1287 map->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS, NULL);
1288 // TODO(bauerb): Remove this once the Google Talk plug-in works nicely with
1289 // click-to-play (b/6090625).
1290 if (old_setting == CONTENT_SETTING_ALLOW &&
1291 default_setting == CONTENT_SETTING_ASK) {
1292 map->SetWebsiteSetting(
1293 ContentSettingsPattern::Wildcard(),
1294 ContentSettingsPattern::Wildcard(),
1295 CONTENT_SETTINGS_TYPE_PLUGINS,
1297 new base::FundamentalValue(CONTENT_SETTING_ALLOW));
1299 prefs->SetInteger(prefs::kContentSettingsDefaultWhitelistVersion,
1300 kDefaultWhitelistVersion);
1303 void ContentSettingsHandler::SetContentFilter(const base::ListValue* args) {
1304 DCHECK_EQ(2U, args->GetSize());
1305 std::string group, setting;
1306 if (!(args->GetString(0, &group) &&
1307 args->GetString(1, &setting))) {
1312 ContentSetting default_setting = ContentSettingFromString(setting);
1313 ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group);
1314 Profile* profile = Profile::FromWebUI(web_ui());
1316 #if defined(OS_CHROMEOS)
1317 // ChromeOS special case : in Guest mode settings are opened in Incognito
1318 // mode, so we need original profile to actually modify settings.
1319 if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
1320 profile = profile->GetOriginalProfile();
1324 HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
1325 ApplyWhitelist(content_type, default_setting);
1326 map->SetDefaultContentSetting(content_type, default_setting);
1328 switch (content_type) {
1329 case CONTENT_SETTINGS_TYPE_COOKIES:
1330 content::RecordAction(
1331 UserMetricsAction("Options_DefaultCookieSettingChanged"));
1333 case CONTENT_SETTINGS_TYPE_IMAGES:
1334 content::RecordAction(
1335 UserMetricsAction("Options_DefaultImagesSettingChanged"));
1337 case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
1338 content::RecordAction(
1339 UserMetricsAction("Options_DefaultJavaScriptSettingChanged"));
1341 case CONTENT_SETTINGS_TYPE_PLUGINS:
1342 content::RecordAction(
1343 UserMetricsAction("Options_DefaultPluginsSettingChanged"));
1345 case CONTENT_SETTINGS_TYPE_POPUPS:
1346 content::RecordAction(
1347 UserMetricsAction("Options_DefaultPopupsSettingChanged"));
1349 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
1350 content::RecordAction(
1351 UserMetricsAction("Options_DefaultNotificationsSettingChanged"));
1353 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
1354 content::RecordAction(
1355 UserMetricsAction("Options_DefaultGeolocationSettingChanged"));
1357 case CONTENT_SETTINGS_TYPE_MOUSELOCK:
1358 content::RecordAction(
1359 UserMetricsAction("Options_DefaultMouseLockSettingChanged"));
1361 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
1362 content::RecordAction(
1363 UserMetricsAction("Options_DefaultMediaStreamMicSettingChanged"));
1365 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
1366 content::RecordAction(
1367 UserMetricsAction("Options_DefaultMultipleAutomaticDLSettingChange"));
1369 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
1370 content::RecordAction(
1371 UserMetricsAction("Options_DefaultMIDISysExSettingChanged"));
1373 case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
1374 content::RecordAction(
1375 UserMetricsAction("Options_DefaultPushMessagingSettingChanged"));
1382 void ContentSettingsHandler::RemoveException(const base::ListValue* args) {
1383 std::string type_string;
1384 CHECK(args->GetString(0, &type_string));
1386 // Zoom levels are no actual content type so we need to handle them
1387 // separately. They would not be recognized by
1388 // ContentSettingsTypeFromGroupName.
1389 if (type_string == kZoomContentType) {
1390 RemoveZoomLevelException(args);
1394 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
1396 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
1397 RemoveNotificationException(args);
1399 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
1400 RemoveMediaException(args);
1403 RemoveExceptionFromHostContentSettingsMap(args, type);
1408 void ContentSettingsHandler::SetException(const base::ListValue* args) {
1409 std::string type_string;
1410 CHECK(args->GetString(0, &type_string));
1412 CHECK(args->GetString(1, &mode));
1413 std::string pattern;
1414 CHECK(args->GetString(2, &pattern));
1415 std::string setting;
1416 CHECK(args->GetString(3, &setting));
1418 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
1419 if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
1420 type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS ||
1421 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM ||
1422 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
1423 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
1426 HostContentSettingsMap* settings_map =
1427 mode == "normal" ? GetContentSettingsMap() :
1428 GetOTRContentSettingsMap();
1430 // The settings map could be null if the mode was OTR but the OTR profile
1431 // got destroyed before we received this message.
1434 settings_map->SetContentSetting(ContentSettingsPattern::FromString(pattern),
1435 ContentSettingsPattern::Wildcard(),
1438 ContentSettingFromString(setting));
1442 void ContentSettingsHandler::CheckExceptionPatternValidity(
1443 const base::ListValue* args) {
1444 std::string type_string;
1445 CHECK(args->GetString(0, &type_string));
1446 std::string mode_string;
1447 CHECK(args->GetString(1, &mode_string));
1448 std::string pattern_string;
1449 CHECK(args->GetString(2, &pattern_string));
1451 ContentSettingsPattern pattern =
1452 ContentSettingsPattern::FromString(pattern_string);
1454 web_ui()->CallJavascriptFunction(
1455 "ContentSettings.patternValidityCheckComplete",
1456 base::StringValue(type_string),
1457 base::StringValue(mode_string),
1458 base::StringValue(pattern_string),
1459 base::FundamentalValue(pattern.IsValid()));
1463 std::string ContentSettingsHandler::ContentSettingsTypeToGroupName(
1464 ContentSettingsType type) {
1465 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) {
1466 if (type == kContentSettingsTypeGroupNames[i].type)
1467 return kContentSettingsTypeGroupNames[i].name;
1471 return std::string();
1474 HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() {
1475 return Profile::FromWebUI(web_ui())->GetHostContentSettingsMap();
1478 ProtocolHandlerRegistry* ContentSettingsHandler::GetProtocolHandlerRegistry() {
1479 return ProtocolHandlerRegistryFactory::GetForBrowserContext(
1480 GetBrowserContext(web_ui()));
1483 HostContentSettingsMap*
1484 ContentSettingsHandler::GetOTRContentSettingsMap() {
1485 Profile* profile = Profile::FromWebUI(web_ui());
1486 if (profile->HasOffTheRecordProfile())
1487 return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
1491 void ContentSettingsHandler::RefreshFlashMediaSettings() {
1492 media_settings_.flash_settings_initialized = false;
1494 media_settings_.last_flash_refresh_request_id =
1495 flash_settings_manager_->GetPermissionSettings(
1496 PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC);
1499 void ContentSettingsHandler::OnPepperFlashPrefChanged() {
1500 ShowFlashMediaLink(DEFAULT_SETTING, false);
1501 ShowFlashMediaLink(EXCEPTIONS, false);
1503 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
1504 if (prefs->GetBoolean(prefs::kPepperFlashSettingsEnabled))
1505 RefreshFlashMediaSettings();
1507 media_settings_.flash_settings_initialized = false;
1510 void ContentSettingsHandler::OnZoomLevelChanged(
1511 const content::HostZoomMap::ZoomLevelChange& change) {
1512 UpdateZoomLevelsExceptionsView();
1515 void ContentSettingsHandler::ShowFlashMediaLink(LinkType link_type, bool show) {
1516 bool& show_link = link_type == DEFAULT_SETTING ?
1517 media_settings_.show_flash_default_link :
1518 media_settings_.show_flash_exceptions_link;
1519 if (show_link != show) {
1520 web_ui()->CallJavascriptFunction(
1521 link_type == DEFAULT_SETTING ?
1522 "ContentSettings.showMediaPepperFlashDefaultLink" :
1523 "ContentSettings.showMediaPepperFlashExceptionsLink",
1524 base::FundamentalValue(show));
1529 void ContentSettingsHandler::UpdateFlashMediaLinksVisibility() {
1530 if (!media_settings_.flash_settings_initialized ||
1531 !media_settings_.default_setting_initialized ||
1532 !media_settings_.exceptions_initialized) {
1536 // Flash won't send us notifications when its settings get changed, which
1537 // means the Flash settings in |media_settings_| may be out-dated, especially
1538 // after we show links to change Flash settings.
1539 // In order to avoid confusion, we won't hide the links once they are showed.
1540 // One exception is that we will hide them when Pepper Flash is disabled
1541 // (handled in OnPepperFlashPrefChanged()).
1542 if (media_settings_.show_flash_default_link &&
1543 media_settings_.show_flash_exceptions_link) {
1547 if (!media_settings_.show_flash_default_link) {
1548 // If both audio and video capture are disabled by policy, the link
1549 // shouldn't be showed. Flash conforms to the policy in this case because
1550 // it cannot open those devices. We don't have to look at the Flash
1552 if (!(media_settings_.policy_disable_audio &&
1553 media_settings_.policy_disable_video) &&
1554 media_settings_.flash_default_setting !=
1555 media_settings_.default_setting) {
1556 ShowFlashMediaLink(DEFAULT_SETTING, true);
1559 if (!media_settings_.show_flash_exceptions_link) {
1560 // If audio or video capture is disabled by policy, we skip comparison of
1561 // exceptions for audio or video capture, respectively.
1562 if (!PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
1563 media_settings_.default_setting,
1564 media_settings_.exceptions,
1565 media_settings_.flash_default_setting,
1566 media_settings_.flash_exceptions,
1567 media_settings_.policy_disable_audio,
1568 media_settings_.policy_disable_video)) {
1569 ShowFlashMediaLink(EXCEPTIONS, true);
1574 void ContentSettingsHandler::UpdateProtectedContentExceptionsButton() {
1575 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
1576 // Exceptions apply only when the feature is enabled.
1577 bool enable_exceptions = prefs->GetBoolean(prefs::kEnableDRM);
1578 web_ui()->CallJavascriptFunction(
1579 "ContentSettings.enableProtectedContentExceptions",
1580 base::FundamentalValue(enable_exceptions));
1583 } // namespace options