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_utils.h"
21 #include "chrome/browser/content_settings/host_content_settings_map.h"
22 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
23 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
24 #include "chrome/browser/extensions/extension_special_storage_policy.h"
25 #include "chrome/browser/notifications/desktop_notification_profile_util.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/ui/browser_list.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/common/url_constants.h"
32 #include "chrome/grit/generated_resources.h"
33 #include "chrome/grit/locale_settings.h"
34 #include "components/content_settings/core/browser/content_settings_details.h"
35 #include "components/content_settings/core/common/content_settings.h"
36 #include "components/content_settings/core/common/content_settings_pattern.h"
37 #include "components/google/core/browser/google_util.h"
38 #include "components/user_prefs/user_prefs.h"
39 #include "content/public/browser/notification_service.h"
40 #include "content/public/browser/notification_source.h"
41 #include "content/public/browser/notification_types.h"
42 #include "content/public/browser/user_metrics.h"
43 #include "content/public/browser/web_contents.h"
44 #include "content/public/browser/web_ui.h"
45 #include "content/public/common/content_switches.h"
46 #include "content/public/common/page_zoom.h"
47 #include "extensions/browser/extension_registry.h"
48 #include "extensions/common/extension_set.h"
49 #include "extensions/common/permissions/api_permission.h"
50 #include "extensions/common/permissions/permissions_data.h"
51 #include "ui/base/l10n/l10n_util.h"
53 #if defined(OS_CHROMEOS)
54 #include "components/user_manager/user_manager.h"
57 using base::UserMetricsAction;
58 using content_settings::ContentSettingToString;
59 using content_settings::ContentSettingFromString;
60 using extensions::APIPermission;
64 struct ContentSettingsTypeNameEntry {
65 ContentSettingsType type;
69 // Maps from a secondary pattern to a setting.
70 typedef std::map<ContentSettingsPattern, ContentSetting>
72 // Maps from a primary pattern/source pair to a OnePatternSettings. All the
73 // mappings in OnePatternSettings share the given primary pattern and source.
74 typedef std::map<std::pair<ContentSettingsPattern, std::string>,
78 // The AppFilter is used in AddExceptionsGrantedByHostedApps() to choose
79 // extensions which should have their extent displayed.
80 typedef bool (*AppFilter)(const extensions::Extension& app,
81 content::BrowserContext* profile);
83 const char kExceptionsLearnMoreUrl[] =
84 "https://support.google.com/chrome/?p=settings_manage_exceptions";
86 const char* kSetting = "setting";
87 const char* kOrigin = "origin";
88 const char* kSource = "source";
89 const char* kAppName = "appName";
90 const char* kAppId = "appId";
91 const char* kEmbeddingOrigin = "embeddingOrigin";
92 const char* kPreferencesSource = "preference";
93 const char* kVideoSetting = "video";
94 const char* kZoom = "zoom";
96 const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = {
97 {CONTENT_SETTINGS_TYPE_COOKIES, "cookies"},
98 {CONTENT_SETTINGS_TYPE_IMAGES, "images"},
99 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, "javascript"},
100 {CONTENT_SETTINGS_TYPE_PLUGINS, "plugins"},
101 {CONTENT_SETTINGS_TYPE_POPUPS, "popups"},
102 {CONTENT_SETTINGS_TYPE_GEOLOCATION, "location"},
103 {CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "notifications"},
104 {CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, "auto-select-certificate"},
105 {CONTENT_SETTINGS_TYPE_FULLSCREEN, "fullscreen"},
106 {CONTENT_SETTINGS_TYPE_MOUSELOCK, "mouselock"},
107 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, "register-protocol-handler"},
108 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, "media-stream"},
109 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, "media-stream-mic"},
110 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, "media-stream-camera"},
111 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, "ppapi-broker"},
112 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, "multiple-automatic-downloads"},
113 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, "midi-sysex"},
114 {CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, "push-messaging"},
115 {CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, "ssl-cert-decisions"},
116 #if defined(OS_CHROMEOS)
117 {CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, "protectedContent"},
121 // A pseudo content type. We use it to display data like a content setting even
122 // though it is not a real content setting.
123 const char* kZoomContentType = "zoomlevels";
125 content::BrowserContext* GetBrowserContext(content::WebUI* web_ui) {
126 return web_ui->GetWebContents()->GetBrowserContext();
129 ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) {
130 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) {
131 if (name == kContentSettingsTypeGroupNames[i].name)
132 return kContentSettingsTypeGroupNames[i].type;
135 NOTREACHED() << name << " is not a recognized content settings type.";
136 return CONTENT_SETTINGS_TYPE_DEFAULT;
139 // Create a DictionaryValue* that will act as a data source for a single row
140 // in a HostContentSettingsMap-controlled exceptions table (e.g., cookies).
141 // Ownership of the pointer is passed to the caller.
142 base::DictionaryValue* GetExceptionForPage(
143 const ContentSettingsPattern& pattern,
144 const ContentSettingsPattern& secondary_pattern,
145 const ContentSetting& setting,
146 const std::string& provider_name) {
147 base::DictionaryValue* exception = new base::DictionaryValue();
148 exception->SetString(kOrigin, pattern.ToString());
149 exception->SetString(kEmbeddingOrigin,
150 secondary_pattern == ContentSettingsPattern::Wildcard() ?
152 secondary_pattern.ToString());
153 exception->SetString(kSetting, ContentSettingToString(setting));
154 exception->SetString(kSource, provider_name);
158 // Create a DictionaryValue* that will act as a data source for a single row
159 // in the Geolocation exceptions table. Ownership of the pointer is passed to
161 base::DictionaryValue* GetGeolocationExceptionForPage(
162 const ContentSettingsPattern& origin,
163 const ContentSettingsPattern& embedding_origin,
164 ContentSetting setting) {
165 base::DictionaryValue* exception = new base::DictionaryValue();
166 exception->SetString(kSetting, ContentSettingToString(setting));
167 exception->SetString(kOrigin, origin.ToString());
168 exception->SetString(kEmbeddingOrigin, embedding_origin.ToString());
172 // Create a DictionaryValue* that will act as a data source for a single row
173 // in the desktop notifications exceptions table. Ownership of the pointer is
174 // passed to the caller.
175 base::DictionaryValue* GetNotificationExceptionForPage(
176 const ContentSettingsPattern& primary_pattern,
177 const ContentSettingsPattern& secondary_pattern,
178 ContentSetting setting,
179 const std::string& provider_name) {
180 std::string embedding_origin;
181 if (secondary_pattern != ContentSettingsPattern::Wildcard())
182 embedding_origin = secondary_pattern.ToString();
184 base::DictionaryValue* exception = new base::DictionaryValue();
185 exception->SetString(kSetting, ContentSettingToString(setting));
186 exception->SetString(kOrigin, primary_pattern.ToString());
187 exception->SetString(kEmbeddingOrigin, embedding_origin);
188 exception->SetString(kSource, provider_name);
192 // Returns true whenever the |extension| is hosted and has |permission|.
193 // Must have the AppFilter signature.
194 template <APIPermission::ID permission>
195 bool HostedAppHasPermission(const extensions::Extension& extension,
196 content::BrowserContext* /* context */) {
197 return extension.is_hosted_app() &&
198 extension.permissions_data()->HasAPIPermission(permission);
201 // Add an "Allow"-entry to the list of |exceptions| for a |url_pattern| from
202 // the web extent of a hosted |app|.
203 void AddExceptionForHostedApp(const std::string& url_pattern,
204 const extensions::Extension& app, base::ListValue* exceptions) {
205 base::DictionaryValue* exception = new base::DictionaryValue();
206 exception->SetString(kSetting, ContentSettingToString(CONTENT_SETTING_ALLOW));
207 exception->SetString(kOrigin, url_pattern);
208 exception->SetString(kEmbeddingOrigin, url_pattern);
209 exception->SetString(kSource, "HostedApp");
210 exception->SetString(kAppName, app.name());
211 exception->SetString(kAppId, app.id());
212 exceptions->Append(exception);
215 // Asks the |profile| for hosted apps which have the |permission| set, and
216 // adds their web extent and launch URL to the |exceptions| list.
217 void AddExceptionsGrantedByHostedApps(content::BrowserContext* context,
218 AppFilter app_filter,
219 base::ListValue* exceptions) {
220 const extensions::ExtensionSet& extensions =
221 extensions::ExtensionRegistry::Get(context)->enabled_extensions();
222 for (extensions::ExtensionSet::const_iterator extension = extensions.begin();
223 extension != extensions.end(); ++extension) {
224 if (!app_filter(*extension->get(), context))
227 extensions::URLPatternSet web_extent = (*extension)->web_extent();
228 // Add patterns from web extent.
229 for (extensions::URLPatternSet::const_iterator pattern = web_extent.begin();
230 pattern != web_extent.end(); ++pattern) {
231 std::string url_pattern = pattern->GetAsString();
232 AddExceptionForHostedApp(url_pattern, *extension->get(), exceptions);
234 // Retrieve the launch URL.
236 extensions::AppLaunchInfo::GetLaunchWebURL(extension->get());
237 // Skip adding the launch URL if it is part of the web extent.
238 if (web_extent.MatchesURL(launch_url))
240 AddExceptionForHostedApp(launch_url.spec(), *extension->get(), exceptions);
244 // Sort ZoomLevelChanges by host and scheme
245 // (a.com < http://a.com < https://a.com < b.com).
246 bool HostZoomSort(const content::HostZoomMap::ZoomLevelChange& a,
247 const content::HostZoomMap::ZoomLevelChange& b) {
248 return a.host == b.host ? a.scheme < b.scheme : a.host < b.host;
255 ContentSettingsHandler::MediaSettingsInfo::MediaSettingsInfo()
256 : flash_default_setting(CONTENT_SETTING_DEFAULT),
257 flash_settings_initialized(false),
258 last_flash_refresh_request_id(0),
259 show_flash_default_link(false),
260 show_flash_exceptions_link(false),
261 default_setting(CONTENT_SETTING_DEFAULT),
262 policy_disable_audio(false),
263 policy_disable_video(false),
264 default_setting_initialized(false),
265 exceptions_initialized(false) {
268 ContentSettingsHandler::MediaSettingsInfo::~MediaSettingsInfo() {
271 ContentSettingsHandler::ContentSettingsHandler() : observer_(this) {
274 ContentSettingsHandler::~ContentSettingsHandler() {
277 void ContentSettingsHandler::GetLocalizedValues(
278 base::DictionaryValue* localized_strings) {
279 DCHECK(localized_strings);
281 // TODO(dhnishi): Standardize to lowerCamelCase.
282 static OptionsStringResource resources[] = {
283 { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON },
284 { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON },
285 { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON },
286 { "askException", IDS_EXCEPTIONS_ASK_BUTTON },
287 { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL },
288 { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS },
289 { "manageExceptions", IDS_EXCEPTIONS_MANAGE },
290 { "manage_handlers", IDS_HANDLERS_MANAGE },
291 { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER },
292 { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER },
293 { "exceptionZoomHeader", IDS_EXCEPTIONS_ZOOM_HEADER },
294 { "embeddedOnHost", IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST },
296 { "cookiesTabLabel", IDS_COOKIES_TAB_LABEL },
297 { "cookies_header", IDS_COOKIES_HEADER },
298 { "cookiesAllow", IDS_COOKIES_ALLOW_RADIO },
299 { "cookiesBlock", IDS_COOKIES_BLOCK_RADIO },
300 { "cookies_session_only", IDS_COOKIES_SESSION_ONLY_RADIO },
301 { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX },
302 { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX },
303 { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX },
304 { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON },
305 { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS },
306 { "flash_storage_url", IDS_FLASH_STORAGE_URL },
307 #if defined(ENABLE_GOOGLE_NOW)
308 { "googleGeolocationAccessEnable",
309 IDS_GEOLOCATION_GOOGLE_ACCESS_ENABLE_CHKBOX },
312 { "imagesTabLabel", IDS_IMAGES_TAB_LABEL },
313 { "images_header", IDS_IMAGES_HEADER },
314 { "imagesAllow", IDS_IMAGES_LOAD_RADIO },
315 { "imagesBlock", IDS_IMAGES_NOLOAD_RADIO },
316 // JavaScript filter.
317 { "javascriptTabLabel", IDS_JAVASCRIPT_TAB_LABEL },
318 { "javascript_header", IDS_JAVASCRIPT_HEADER },
319 { "javascriptAllow", IDS_JS_ALLOW_RADIO },
320 { "javascriptBlock", IDS_JS_DONOTALLOW_RADIO },
322 { "pluginsTabLabel", IDS_PLUGIN_TAB_LABEL },
323 { "plugins_header", IDS_PLUGIN_HEADER },
324 { "pluginsAsk", IDS_PLUGIN_ASK_RADIO },
325 { "pluginsAllow", IDS_PLUGIN_LOAD_RADIO },
326 { "pluginsBlock", IDS_PLUGIN_NOLOAD_RADIO },
327 { "disableIndividualPlugins", IDS_PLUGIN_SELECTIVE_DISABLE },
329 { "popupsTabLabel", IDS_POPUP_TAB_LABEL },
330 { "popups_header", IDS_POPUP_HEADER },
331 { "popupsAllow", IDS_POPUP_ALLOW_RADIO },
332 { "popupsBlock", IDS_POPUP_BLOCK_RADIO },
334 { "locationTabLabel", IDS_GEOLOCATION_TAB_LABEL },
335 { "location_header", IDS_GEOLOCATION_HEADER },
336 { "locationAllow", IDS_GEOLOCATION_ALLOW_RADIO },
337 { "locationAsk", IDS_GEOLOCATION_ASK_RADIO },
338 { "locationBlock", IDS_GEOLOCATION_BLOCK_RADIO },
339 { "set_by", IDS_GEOLOCATION_SET_BY_HOVER },
340 // Notifications filter.
341 { "notificationsTabLabel", IDS_NOTIFICATIONS_TAB_LABEL },
342 { "notifications_header", IDS_NOTIFICATIONS_HEADER },
343 { "notificationsAllow", IDS_NOTIFICATIONS_ALLOW_RADIO },
344 { "notificationsAsk", IDS_NOTIFICATIONS_ASK_RADIO },
345 { "notificationsBlock", IDS_NOTIFICATIONS_BLOCK_RADIO },
346 // Fullscreen filter.
347 { "fullscreenTabLabel", IDS_FULLSCREEN_TAB_LABEL },
348 { "fullscreen_header", IDS_FULLSCREEN_HEADER },
349 // Mouse Lock filter.
350 { "mouselockTabLabel", IDS_MOUSE_LOCK_TAB_LABEL },
351 { "mouselock_header", IDS_MOUSE_LOCK_HEADER },
352 { "mouselockAllow", IDS_MOUSE_LOCK_ALLOW_RADIO },
353 { "mouselockAsk", IDS_MOUSE_LOCK_ASK_RADIO },
354 { "mouselockBlock", IDS_MOUSE_LOCK_BLOCK_RADIO },
355 #if defined(OS_CHROMEOS) || defined(OS_WIN)
356 // Protected Content filter
357 { "protectedContentTabLabel", IDS_PROTECTED_CONTENT_TAB_LABEL },
358 { "protectedContentInfo", IDS_PROTECTED_CONTENT_INFO },
359 { "protectedContentEnable", IDS_PROTECTED_CONTENT_ENABLE },
360 { "protectedContent_header", IDS_PROTECTED_CONTENT_HEADER },
361 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
362 // Media stream capture device filter.
363 { "mediaStreamTabLabel", IDS_MEDIA_STREAM_TAB_LABEL },
364 { "media-stream_header", IDS_MEDIA_STREAM_HEADER },
365 { "mediaStreamAsk", IDS_MEDIA_STREAM_ASK_RADIO },
366 { "mediaStreamBlock", IDS_MEDIA_STREAM_BLOCK_RADIO },
367 { "mediaStreamAudioAsk", IDS_MEDIA_STREAM_ASK_AUDIO_ONLY_RADIO },
368 { "mediaStreamAudioBlock", IDS_MEDIA_STREAM_BLOCK_AUDIO_ONLY_RADIO },
369 { "mediaStreamVideoAsk", IDS_MEDIA_STREAM_ASK_VIDEO_ONLY_RADIO },
370 { "mediaStreamVideoBlock", IDS_MEDIA_STREAM_BLOCK_VIDEO_ONLY_RADIO },
371 { "mediaStreamBubbleAudio", IDS_MEDIA_STREAM_AUDIO_MANAGED },
372 { "mediaStreamBubbleVideo", IDS_MEDIA_STREAM_VIDEO_MANAGED },
373 { "mediaAudioExceptionHeader", IDS_MEDIA_AUDIO_EXCEPTION_HEADER },
374 { "mediaVideoExceptionHeader", IDS_MEDIA_VIDEO_EXCEPTION_HEADER },
375 { "mediaPepperFlashDefaultDivergedLabel",
376 IDS_MEDIA_PEPPER_FLASH_DEFAULT_DIVERGED_LABEL },
377 { "mediaPepperFlashExceptionsDivergedLabel",
378 IDS_MEDIA_PEPPER_FLASH_EXCEPTIONS_DIVERGED_LABEL },
379 { "mediaPepperFlashChangeLink", IDS_MEDIA_PEPPER_FLASH_CHANGE_LINK },
380 { "mediaPepperFlashGlobalPrivacyURL", IDS_FLASH_GLOBAL_PRIVACY_URL },
381 { "mediaPepperFlashWebsitePrivacyURL", IDS_FLASH_WEBSITE_PRIVACY_URL },
382 // PPAPI broker filter.
383 { "ppapi-broker_header", IDS_PPAPI_BROKER_HEADER },
384 { "ppapiBrokerTabLabel", IDS_PPAPI_BROKER_TAB_LABEL },
385 { "ppapiBrokerAllow", IDS_PPAPI_BROKER_ALLOW_RADIO },
386 { "ppapiBrokerAsk", IDS_PPAPI_BROKER_ASK_RADIO },
387 { "ppapiBrokerBlock", IDS_PPAPI_BROKER_BLOCK_RADIO },
388 // Multiple automatic downloads
389 { "multipleAutomaticDownloadsTabLabel",
390 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL },
391 { "multipleAutomaticDownloadsAllow",
392 IDS_AUTOMATIC_DOWNLOADS_ALLOW_RADIO },
393 { "multipleAutomaticDownloadsAsk",
394 IDS_AUTOMATIC_DOWNLOADS_ASK_RADIO },
395 { "multipleAutomaticDownloadsBlock",
396 IDS_AUTOMATIC_DOWNLOADS_BLOCK_RADIO },
397 // MIDI system exclusive messages
398 { "midi-sysex_header", IDS_MIDI_SYSEX_TAB_LABEL },
399 { "midiSysExAllow", IDS_MIDI_SYSEX_ALLOW_RADIO },
400 { "midiSysExAsk", IDS_MIDI_SYSEX_ASK_RADIO },
401 { "midiSysExBlock", IDS_MIDI_SYSEX_BLOCK_RADIO },
402 // Push messaging strings
403 { "push-messaging_header", IDS_PUSH_MESSAGES_TAB_LABEL },
404 { "pushMessagingAllow", IDS_PUSH_MESSSAGING_ALLOW_RADIO },
405 { "pushMessagingAsk", IDS_PUSH_MESSSAGING_ASK_RADIO },
406 { "pushMessagingBlock", IDS_PUSH_MESSSAGING_BLOCK_RADIO },
407 { "zoomlevels_header", IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL },
408 { "zoomLevelsManage", IDS_ZOOMLEVELS_MANAGE_BUTTON },
411 RegisterStrings(localized_strings, resources, arraysize(resources));
412 RegisterTitle(localized_strings, "contentSettingsPage",
413 IDS_CONTENT_SETTINGS_TITLE);
415 // Register titles for each of the individual settings whose exception
416 // dialogs will be processed by |ContentSettingsHandler|.
417 RegisterTitle(localized_strings, "cookies",
418 IDS_COOKIES_TAB_LABEL);
419 RegisterTitle(localized_strings, "images",
420 IDS_IMAGES_TAB_LABEL);
421 RegisterTitle(localized_strings, "javascript",
422 IDS_JAVASCRIPT_TAB_LABEL);
423 RegisterTitle(localized_strings, "plugins",
424 IDS_PLUGIN_TAB_LABEL);
425 RegisterTitle(localized_strings, "popups",
426 IDS_POPUP_TAB_LABEL);
427 RegisterTitle(localized_strings, "location",
428 IDS_GEOLOCATION_TAB_LABEL);
429 RegisterTitle(localized_strings, "notifications",
430 IDS_NOTIFICATIONS_TAB_LABEL);
431 RegisterTitle(localized_strings, "fullscreen",
432 IDS_FULLSCREEN_TAB_LABEL);
433 RegisterTitle(localized_strings, "mouselock",
434 IDS_MOUSE_LOCK_TAB_LABEL);
435 #if defined(OS_CHROMEOS)
436 RegisterTitle(localized_strings, "protectedContent",
437 IDS_PROTECTED_CONTENT_TAB_LABEL);
439 RegisterTitle(localized_strings, "media-stream",
440 IDS_MEDIA_STREAM_TAB_LABEL);
441 RegisterTitle(localized_strings, "ppapi-broker",
442 IDS_PPAPI_BROKER_TAB_LABEL);
443 RegisterTitle(localized_strings, "multiple-automatic-downloads",
444 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL);
445 RegisterTitle(localized_strings, "midi-sysex",
446 IDS_MIDI_SYSEX_TAB_LABEL);
447 RegisterTitle(localized_strings, "zoomlevels",
448 IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL);
450 localized_strings->SetString("exceptionsLearnMoreUrl",
451 kExceptionsLearnMoreUrl);
454 void ContentSettingsHandler::InitializeHandler() {
455 notification_registrar_.Add(
456 this, chrome::NOTIFICATION_PROFILE_CREATED,
457 content::NotificationService::AllSources());
458 notification_registrar_.Add(
459 this, chrome::NOTIFICATION_PROFILE_DESTROYED,
460 content::NotificationService::AllSources());
462 notification_registrar_.Add(
463 this, chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
464 content::NotificationService::AllSources());
465 content::BrowserContext* context = GetBrowserContext(web_ui());
466 notification_registrar_.Add(
467 this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
468 content::Source<content::BrowserContext>(context));
470 PrefService* prefs = user_prefs::UserPrefs::Get(context);
471 pref_change_registrar_.Init(prefs);
472 pref_change_registrar_.Add(
473 prefs::kPepperFlashSettingsEnabled,
474 base::Bind(&ContentSettingsHandler::OnPepperFlashPrefChanged,
475 base::Unretained(this)));
476 pref_change_registrar_.Add(
477 prefs::kAudioCaptureAllowed,
478 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView,
479 base::Unretained(this)));
480 pref_change_registrar_.Add(
481 prefs::kVideoCaptureAllowed,
482 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView,
483 base::Unretained(this)));
484 pref_change_registrar_.Add(
487 &ContentSettingsHandler::UpdateProtectedContentExceptionsButton,
488 base::Unretained(this)));
490 content::HostZoomMap* host_zoom_map =
491 content::HostZoomMap::GetDefaultForBrowserContext(context);
492 host_zoom_map_subscription_ =
493 host_zoom_map->AddZoomLevelChangedCallback(
494 base::Bind(&ContentSettingsHandler::OnZoomLevelChanged,
495 base::Unretained(this)));
497 flash_settings_manager_.reset(new PepperFlashSettingsManager(this, context));
499 Profile* profile = Profile::FromWebUI(web_ui());
500 observer_.Add(profile->GetHostContentSettingsMap());
501 if (profile->HasOffTheRecordProfile()) {
502 auto map = profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
503 if (!observer_.IsObserving(map))
508 void ContentSettingsHandler::InitializePage() {
509 media_settings_ = MediaSettingsInfo();
510 RefreshFlashMediaSettings();
512 UpdateHandlersEnabledRadios();
513 UpdateAllExceptionsViewsFromModel();
514 UpdateProtectedContentExceptionsButton();
517 void ContentSettingsHandler::OnContentSettingChanged(
518 const ContentSettingsPattern& primary_pattern,
519 const ContentSettingsPattern& secondary_pattern,
520 ContentSettingsType content_type,
521 std::string resource_identifier) {
522 const ContentSettingsDetails details(
523 primary_pattern, secondary_pattern, content_type, resource_identifier);
524 // TODO(estade): we pretend update_all() is always true.
525 if (details.update_all_types())
526 UpdateAllExceptionsViewsFromModel();
528 UpdateExceptionsViewFromModel(details.type());
531 void ContentSettingsHandler::Observe(
533 const content::NotificationSource& source,
534 const content::NotificationDetails& details) {
536 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
537 Profile* profile = content::Source<Profile>(source).ptr();
538 if (profile->IsOffTheRecord() &&
539 observer_.IsObserving(profile->GetHostContentSettingsMap())) {
540 web_ui()->CallJavascriptFunction(
541 "ContentSettingsExceptionsArea.OTRProfileDestroyed");
542 observer_.Remove(profile->GetHostContentSettingsMap());
547 case chrome::NOTIFICATION_PROFILE_CREATED: {
548 Profile* profile = content::Source<Profile>(source).ptr();
549 if (profile->IsOffTheRecord()) {
550 UpdateAllOTRExceptionsViewsFromModel();
551 observer_.Add(profile->GetHostContentSettingsMap());
556 case chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED: {
557 UpdateNotificationExceptionsView();
561 case chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED: {
562 UpdateHandlersEnabledRadios();
568 void ContentSettingsHandler::OnGetPermissionSettingsCompleted(
571 PP_Flash_BrowserOperations_Permission default_permission,
572 const ppapi::FlashSiteSettings& sites) {
573 if (success && request_id == media_settings_.last_flash_refresh_request_id) {
574 media_settings_.flash_settings_initialized = true;
575 media_settings_.flash_default_setting =
576 PepperFlashContentSettingsUtils::FlashPermissionToContentSetting(
578 PepperFlashContentSettingsUtils::FlashSiteSettingsToMediaExceptions(
579 sites, &media_settings_.flash_exceptions);
580 PepperFlashContentSettingsUtils::SortMediaExceptions(
581 &media_settings_.flash_exceptions);
583 UpdateFlashMediaLinksVisibility();
587 void ContentSettingsHandler::UpdateSettingDefaultFromModel(
588 ContentSettingsType type) {
589 base::DictionaryValue filter_settings;
590 std::string provider_id;
591 filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value",
592 GetSettingDefaultFromModel(type, &provider_id));
593 filter_settings.SetString(
594 ContentSettingsTypeToGroupName(type) + ".managedBy", provider_id);
596 web_ui()->CallJavascriptFunction(
597 "ContentSettings.setContentFilterSettingsValue", filter_settings);
600 void ContentSettingsHandler::UpdateMediaSettingsView() {
601 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
602 bool audio_disabled = !prefs->GetBoolean(prefs::kAudioCaptureAllowed) &&
603 prefs->IsManagedPreference(prefs::kAudioCaptureAllowed);
604 bool video_disabled = !prefs->GetBoolean(prefs::kVideoCaptureAllowed) &&
605 prefs->IsManagedPreference(prefs::kVideoCaptureAllowed);
607 media_settings_.policy_disable_audio = audio_disabled;
608 media_settings_.policy_disable_video = video_disabled;
609 media_settings_.default_setting =
610 GetContentSettingsMap()->GetDefaultContentSetting(
611 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL);
612 media_settings_.default_setting_initialized = true;
613 UpdateFlashMediaLinksVisibility();
615 base::DictionaryValue media_ui_settings;
616 media_ui_settings.SetBoolean("cameraDisabled", video_disabled);
617 media_ui_settings.SetBoolean("micDisabled", audio_disabled);
619 // In case only video is enabled change the text appropriately.
620 if (audio_disabled && !video_disabled) {
621 media_ui_settings.SetString("askText", "mediaStreamVideoAsk");
622 media_ui_settings.SetString("blockText", "mediaStreamVideoBlock");
623 media_ui_settings.SetBoolean("showBubble", true);
624 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleAudio");
626 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
631 // In case only audio is enabled change the text appropriately.
632 if (video_disabled && !audio_disabled) {
633 base::DictionaryValue media_ui_settings;
634 media_ui_settings.SetString("askText", "mediaStreamAudioAsk");
635 media_ui_settings.SetString("blockText", "mediaStreamAudioBlock");
636 media_ui_settings.SetBoolean("showBubble", true);
637 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleVideo");
639 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
644 if (audio_disabled && video_disabled) {
645 // Fake policy controlled default because the user can not change anything
646 // until both audio and video are blocked.
647 base::DictionaryValue filter_settings;
648 std::string group_name =
649 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
650 filter_settings.SetString(group_name + ".value",
651 ContentSettingToString(CONTENT_SETTING_BLOCK));
652 filter_settings.SetString(group_name + ".managedBy", "policy");
653 web_ui()->CallJavascriptFunction(
654 "ContentSettings.setContentFilterSettingsValue", filter_settings);
657 media_ui_settings.SetString("askText", "mediaStreamAsk");
658 media_ui_settings.SetString("blockText", "mediaStreamBlock");
659 media_ui_settings.SetBoolean("showBubble", false);
660 media_ui_settings.SetString("bubbleText", std::string());
662 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
666 std::string ContentSettingsHandler::GetSettingDefaultFromModel(
667 ContentSettingsType type, std::string* provider_id) {
668 Profile* profile = Profile::FromWebUI(web_ui());
669 ContentSetting default_setting;
671 profile->GetHostContentSettingsMap()->GetDefaultContentSetting(
674 return ContentSettingToString(default_setting);
677 void ContentSettingsHandler::UpdateHandlersEnabledRadios() {
678 base::FundamentalValue handlers_enabled(
679 GetProtocolHandlerRegistry()->enabled());
681 web_ui()->CallJavascriptFunction(
682 "ContentSettings.updateHandlersEnabledRadios",
686 void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() {
687 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
688 type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
689 UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
691 // Zoom levels are not actually a content type so we need to handle them
693 UpdateZoomLevelsExceptionsView();
696 void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() {
697 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
698 type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
699 UpdateOTRExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
703 void ContentSettingsHandler::UpdateExceptionsViewFromModel(
704 ContentSettingsType type) {
706 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
707 UpdateGeolocationExceptionsView();
709 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
710 UpdateNotificationExceptionsView();
712 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
713 UpdateMediaSettingsView();
715 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
716 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
717 UpdateMediaExceptionsView();
719 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
720 // We don't yet support exceptions for mixed scripting.
722 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
723 // The content settings type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE
724 // is supposed to be set by policy only. Hence there is no user facing UI
725 // for this content type and we skip it here.
727 case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS:
728 // The RPH settings are retrieved separately.
730 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
731 UpdateMIDISysExExceptionsView();
733 case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS:
734 // The content settings type CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS is
735 // supposed to be set by flags and field trials only, thus there is no
736 // user facing UI for this content type and we skip it here.
739 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
743 UpdateExceptionsViewFromHostContentSettingsMap(type);
748 void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel(
749 ContentSettingsType type) {
751 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
752 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
753 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
754 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
756 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
758 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
759 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
760 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
761 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
762 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
763 case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS:
766 UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
771 // TODO(estade): merge with GetExceptionsFromHostContentSettingsMap.
772 void ContentSettingsHandler::UpdateGeolocationExceptionsView() {
773 Profile* profile = Profile::FromWebUI(web_ui());
774 HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
776 ContentSettingsForOneType all_settings;
777 map->GetSettingsForOneType(
778 CONTENT_SETTINGS_TYPE_GEOLOCATION,
782 // Group geolocation settings by primary_pattern.
783 AllPatternsSettings all_patterns_settings;
784 for (ContentSettingsForOneType::iterator i = all_settings.begin();
785 i != all_settings.end(); ++i) {
786 // Don't add default settings.
787 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
788 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
789 i->source != kPreferencesSource) {
792 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
793 [i->secondary_pattern] = i->setting;
796 base::ListValue exceptions;
797 AddExceptionsGrantedByHostedApps(
799 HostedAppHasPermission<APIPermission::kGeolocation>,
802 for (AllPatternsSettings::iterator i = all_patterns_settings.begin();
803 i != all_patterns_settings.end(); ++i) {
804 const ContentSettingsPattern& primary_pattern = i->first.first;
805 const OnePatternSettings& one_settings = i->second;
807 OnePatternSettings::const_iterator parent =
808 one_settings.find(primary_pattern);
810 // Add the "parent" entry for the non-embedded setting.
811 ContentSetting parent_setting =
812 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
813 exceptions.Append(GetGeolocationExceptionForPage(primary_pattern,
817 // Add the "children" for any embedded settings.
818 for (OnePatternSettings::const_iterator j = one_settings.begin();
819 j != one_settings.end();
821 // Skip the non-embedded setting which we already added above.
825 exceptions.Append(GetGeolocationExceptionForPage(
826 primary_pattern, j->first, j->second));
830 base::StringValue type_string(
831 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION));
832 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
833 type_string, exceptions);
835 // This is mainly here to keep this function ideologically parallel to
836 // UpdateExceptionsViewFromHostContentSettingsMap().
837 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION);
840 void ContentSettingsHandler::UpdateNotificationExceptionsView() {
841 Profile* profile = Profile::FromWebUI(web_ui());
842 ContentSettingsForOneType settings;
843 DesktopNotificationProfileUtil::GetNotificationsSettings(profile, &settings);
845 base::ListValue exceptions;
846 AddExceptionsGrantedByHostedApps(
848 HostedAppHasPermission<APIPermission::kNotifications>,
851 for (ContentSettingsForOneType::const_iterator i =
855 // Don't add default settings.
856 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
857 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
858 i->source != kPreferencesSource) {
863 GetNotificationExceptionForPage(i->primary_pattern,
864 i->secondary_pattern,
869 base::StringValue type_string(
870 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
871 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
872 type_string, exceptions);
874 // This is mainly here to keep this function ideologically parallel to
875 // UpdateExceptionsViewFromHostContentSettingsMap().
876 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
879 void ContentSettingsHandler::UpdateMediaExceptionsView() {
880 base::ListValue media_exceptions;
881 GetExceptionsFromHostContentSettingsMap(
882 GetContentSettingsMap(),
883 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
886 base::ListValue video_exceptions;
887 GetExceptionsFromHostContentSettingsMap(
888 GetContentSettingsMap(),
889 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
892 // Merge the |video_exceptions| list to |media_exceptions| list.
893 std::map<std::string, base::DictionaryValue*> entries_map;
894 for (base::ListValue::const_iterator media_entry(media_exceptions.begin());
895 media_entry != media_exceptions.end(); ++media_entry) {
896 base::DictionaryValue* media_dict = NULL;
897 if (!(*media_entry)->GetAsDictionary(&media_dict))
900 media_dict->SetString(kVideoSetting,
901 ContentSettingToString(CONTENT_SETTING_ASK));
903 std::string media_origin;
904 media_dict->GetString(kOrigin, &media_origin);
905 entries_map[media_origin] = media_dict;
908 for (base::ListValue::iterator video_entry = video_exceptions.begin();
909 video_entry != video_exceptions.end(); ++video_entry) {
910 base::DictionaryValue* video_dict = NULL;
911 if (!(*video_entry)->GetAsDictionary(&video_dict))
914 std::string video_origin;
915 std::string video_setting;
916 video_dict->GetString(kOrigin, &video_origin);
917 video_dict->GetString(kSetting, &video_setting);
919 std::map<std::string, base::DictionaryValue*>::iterator iter =
920 entries_map.find(video_origin);
921 if (iter == entries_map.end()) {
922 base::DictionaryValue* exception = new base::DictionaryValue();
923 exception->SetString(kOrigin, video_origin);
924 exception->SetString(kSetting,
925 ContentSettingToString(CONTENT_SETTING_ASK));
926 exception->SetString(kVideoSetting, video_setting);
927 exception->SetString(kSource, kPreferencesSource);
929 // Append the new entry to the list and map.
930 media_exceptions.Append(exception);
931 entries_map[video_origin] = exception;
933 // Modify the existing entry.
934 iter->second->SetString(kVideoSetting, video_setting);
938 media_settings_.exceptions.clear();
939 for (base::ListValue::const_iterator media_entry = media_exceptions.begin();
940 media_entry != media_exceptions.end(); ++media_entry) {
941 base::DictionaryValue* media_dict = NULL;
942 bool result = (*media_entry)->GetAsDictionary(&media_dict);
946 std::string audio_setting;
947 std::string video_setting;
948 media_dict->GetString(kOrigin, &origin);
949 media_dict->GetString(kSetting, &audio_setting);
950 media_dict->GetString(kVideoSetting, &video_setting);
951 media_settings_.exceptions.push_back(MediaException(
952 ContentSettingsPattern::FromString(origin),
953 ContentSettingFromString(audio_setting),
954 ContentSettingFromString(video_setting)));
956 PepperFlashContentSettingsUtils::SortMediaExceptions(
957 &media_settings_.exceptions);
958 media_settings_.exceptions_initialized = true;
959 UpdateFlashMediaLinksVisibility();
961 base::StringValue type_string(
962 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM));
963 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
964 type_string, media_exceptions);
966 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
969 void ContentSettingsHandler::UpdateMIDISysExExceptionsView() {
970 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebMIDI)) {
971 web_ui()->CallJavascriptFunction(
972 "ContentSettings.showExperimentalWebMIDISettings",
973 base::FundamentalValue(true));
976 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
977 UpdateExceptionsViewFromHostContentSettingsMap(
978 CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
981 void ContentSettingsHandler::UpdateZoomLevelsExceptionsView() {
982 base::ListValue zoom_levels_exceptions;
984 content::HostZoomMap* host_zoom_map =
985 content::HostZoomMap::GetDefaultForBrowserContext(
986 GetBrowserContext(web_ui()));
987 content::HostZoomMap::ZoomLevelVector zoom_levels(
988 host_zoom_map->GetAllZoomLevels());
989 std::sort(zoom_levels.begin(), zoom_levels.end(), HostZoomSort);
991 for (content::HostZoomMap::ZoomLevelVector::const_iterator i =
993 i != zoom_levels.end();
995 scoped_ptr<base::DictionaryValue> exception(new base::DictionaryValue);
997 case content::HostZoomMap::ZOOM_CHANGED_FOR_HOST:
998 exception->SetString(kOrigin, i->host);
1000 case content::HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST:
1001 // These are not stored in preferences and get cleared on next browser
1002 // start. Therefore, we don't care for them.
1004 case content::HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM:
1007 exception->SetString(kSetting,
1008 ContentSettingToString(CONTENT_SETTING_DEFAULT));
1010 // Calculate the zoom percent from the factor. Round up to the nearest whole
1012 int zoom_percent = static_cast<int>(
1013 content::ZoomLevelToZoomFactor(i->zoom_level) * 100 + 0.5);
1014 exception->SetString(
1016 l10n_util::GetStringFUTF16(IDS_ZOOM_PERCENT,
1017 base::IntToString16(zoom_percent)));
1018 exception->SetString(kSource, kPreferencesSource);
1019 // Append the new entry to the list and map.
1020 zoom_levels_exceptions.Append(exception.release());
1023 base::StringValue type_string(kZoomContentType);
1024 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
1025 type_string, zoom_levels_exceptions);
1028 void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap(
1029 ContentSettingsType type) {
1030 base::ListValue exceptions;
1031 GetExceptionsFromHostContentSettingsMap(
1032 GetContentSettingsMap(), type, &exceptions);
1033 base::StringValue type_string(ContentSettingsTypeToGroupName(type));
1034 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", type_string,
1037 UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
1039 // TODO(koz): The default for fullscreen is always 'ask'.
1040 // http://crbug.com/104683
1041 if (type == CONTENT_SETTINGS_TYPE_FULLSCREEN)
1044 #if defined(OS_CHROMEOS)
1045 // Also the default for protected contents is managed in another place.
1046 if (type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER)
1050 // The default may also have changed (we won't get a separate notification).
1051 // If it hasn't changed, this call will be harmless.
1052 UpdateSettingDefaultFromModel(type);
1055 void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap(
1056 ContentSettingsType type) {
1057 const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap();
1058 if (!otr_settings_map)
1060 base::ListValue exceptions;
1061 GetExceptionsFromHostContentSettingsMap(otr_settings_map, type, &exceptions);
1062 base::StringValue type_string(ContentSettingsTypeToGroupName(type));
1063 web_ui()->CallJavascriptFunction("ContentSettings.setOTRExceptions",
1064 type_string, exceptions);
1067 void ContentSettingsHandler::GetExceptionsFromHostContentSettingsMap(
1068 const HostContentSettingsMap* map,
1069 ContentSettingsType type,
1070 base::ListValue* exceptions) {
1071 ContentSettingsForOneType entries;
1072 map->GetSettingsForOneType(type, std::string(), &entries);
1073 // Group settings by primary_pattern.
1074 AllPatternsSettings all_patterns_settings;
1075 for (ContentSettingsForOneType::iterator i = entries.begin();
1076 i != entries.end(); ++i) {
1077 // Don't add default settings.
1078 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
1079 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
1080 i->source != kPreferencesSource) {
1084 // Off-the-record HostContentSettingsMap contains incognito content settings
1085 // as well as normal content settings. Here, we use the incongnito settings
1087 if (map->is_off_the_record() && !i->incognito)
1090 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
1091 [i->secondary_pattern] = i->setting;
1094 // Keep the exceptions sorted by provider so they will be displayed in
1095 // precedence order.
1096 std::vector<std::vector<base::Value*> > all_provider_exceptions;
1097 all_provider_exceptions.resize(HostContentSettingsMap::NUM_PROVIDER_TYPES);
1099 for (AllPatternsSettings::iterator i = all_patterns_settings.begin();
1100 i != all_patterns_settings.end();
1102 const ContentSettingsPattern& primary_pattern = i->first.first;
1103 const OnePatternSettings& one_settings = i->second;
1105 // The "parent" entry either has an identical primary and secondary pattern,
1106 // or has a wildcard secondary. The two cases are indistinguishable in the
1108 OnePatternSettings::const_iterator parent =
1109 one_settings.find(primary_pattern);
1110 if (parent == one_settings.end())
1111 parent = one_settings.find(ContentSettingsPattern::Wildcard());
1113 const std::string& source = i->first.second;
1114 std::vector<base::Value*>* this_provider_exceptions =
1115 &all_provider_exceptions.at(
1116 HostContentSettingsMap::GetProviderTypeFromSource(source));
1118 // Add the "parent" entry for the non-embedded setting.
1119 ContentSetting parent_setting =
1120 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
1121 const ContentSettingsPattern& secondary_pattern =
1122 parent == one_settings.end() ? primary_pattern : parent->first;
1123 this_provider_exceptions->push_back(GetExceptionForPage(primary_pattern,
1128 // Add the "children" for any embedded settings.
1129 for (OnePatternSettings::const_iterator j = one_settings.begin();
1130 j != one_settings.end(); ++j) {
1131 // Skip the non-embedded setting which we already added above.
1135 ContentSetting content_setting = j->second;
1136 this_provider_exceptions->push_back(GetExceptionForPage(
1144 for (size_t i = 0; i < all_provider_exceptions.size(); ++i) {
1145 for (size_t j = 0; j < all_provider_exceptions[i].size(); ++j) {
1146 exceptions->Append(all_provider_exceptions[i][j]);
1151 void ContentSettingsHandler::RemoveMediaException(const base::ListValue* args) {
1153 bool rv = args->GetString(1, &mode);
1156 std::string pattern;
1157 rv = args->GetString(2, &pattern);
1160 HostContentSettingsMap* settings_map =
1161 mode == "normal" ? GetContentSettingsMap() :
1162 GetOTRContentSettingsMap();
1164 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1165 ContentSettingsPattern::Wildcard(),
1166 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
1169 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1170 ContentSettingsPattern::Wildcard(),
1171 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
1177 void ContentSettingsHandler::RemoveExceptionFromHostContentSettingsMap(
1178 const base::ListValue* args,
1179 ContentSettingsType type) {
1181 bool rv = args->GetString(1, &mode);
1184 std::string pattern;
1185 rv = args->GetString(2, &pattern);
1188 // The fourth argument to this handler is optional.
1189 std::string secondary_pattern;
1190 if (args->GetSize() >= 4U) {
1191 rv = args->GetString(3, &secondary_pattern);
1195 HostContentSettingsMap* settings_map =
1196 mode == "normal" ? GetContentSettingsMap() :
1197 GetOTRContentSettingsMap();
1199 settings_map->SetWebsiteSetting(
1200 ContentSettingsPattern::FromString(pattern),
1201 secondary_pattern.empty() ?
1202 ContentSettingsPattern::Wildcard() :
1203 ContentSettingsPattern::FromString(secondary_pattern),
1210 void ContentSettingsHandler::RemoveZoomLevelException(
1211 const base::ListValue* args) {
1213 bool rv = args->GetString(1, &mode);
1216 std::string pattern;
1217 rv = args->GetString(2, &pattern);
1220 content::HostZoomMap* host_zoom_map =
1221 content::HostZoomMap::GetDefaultForBrowserContext(
1222 GetBrowserContext(web_ui()));
1223 double default_level = host_zoom_map->GetDefaultZoomLevel();
1224 host_zoom_map->SetZoomLevelForHost(pattern, default_level);
1227 void ContentSettingsHandler::RegisterMessages() {
1228 web_ui()->RegisterMessageCallback("setContentFilter",
1229 base::Bind(&ContentSettingsHandler::SetContentFilter,
1230 base::Unretained(this)));
1231 web_ui()->RegisterMessageCallback("removeException",
1232 base::Bind(&ContentSettingsHandler::RemoveException,
1233 base::Unretained(this)));
1234 web_ui()->RegisterMessageCallback("setException",
1235 base::Bind(&ContentSettingsHandler::SetException,
1236 base::Unretained(this)));
1237 web_ui()->RegisterMessageCallback("checkExceptionPatternValidity",
1238 base::Bind(&ContentSettingsHandler::CheckExceptionPatternValidity,
1239 base::Unretained(this)));
1242 void ContentSettingsHandler::SetContentFilter(const base::ListValue* args) {
1243 DCHECK_EQ(2U, args->GetSize());
1244 std::string group, setting;
1245 if (!(args->GetString(0, &group) &&
1246 args->GetString(1, &setting))) {
1251 ContentSetting default_setting = ContentSettingFromString(setting);
1252 ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group);
1253 Profile* profile = Profile::FromWebUI(web_ui());
1255 #if defined(OS_CHROMEOS)
1256 // ChromeOS special case : in Guest mode settings are opened in Incognito
1257 // mode, so we need original profile to actually modify settings.
1258 if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
1259 profile = profile->GetOriginalProfile();
1263 HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
1264 map->SetDefaultContentSetting(content_type, default_setting);
1266 switch (content_type) {
1267 case CONTENT_SETTINGS_TYPE_COOKIES:
1268 content::RecordAction(
1269 UserMetricsAction("Options_DefaultCookieSettingChanged"));
1271 case CONTENT_SETTINGS_TYPE_IMAGES:
1272 content::RecordAction(
1273 UserMetricsAction("Options_DefaultImagesSettingChanged"));
1275 case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
1276 content::RecordAction(
1277 UserMetricsAction("Options_DefaultJavaScriptSettingChanged"));
1279 case CONTENT_SETTINGS_TYPE_PLUGINS:
1280 content::RecordAction(
1281 UserMetricsAction("Options_DefaultPluginsSettingChanged"));
1283 case CONTENT_SETTINGS_TYPE_POPUPS:
1284 content::RecordAction(
1285 UserMetricsAction("Options_DefaultPopupsSettingChanged"));
1287 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
1288 content::RecordAction(
1289 UserMetricsAction("Options_DefaultNotificationsSettingChanged"));
1291 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
1292 content::RecordAction(
1293 UserMetricsAction("Options_DefaultGeolocationSettingChanged"));
1295 case CONTENT_SETTINGS_TYPE_MOUSELOCK:
1296 content::RecordAction(
1297 UserMetricsAction("Options_DefaultMouseLockSettingChanged"));
1299 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
1300 content::RecordAction(
1301 UserMetricsAction("Options_DefaultMediaStreamMicSettingChanged"));
1303 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
1304 content::RecordAction(
1305 UserMetricsAction("Options_DefaultMultipleAutomaticDLSettingChange"));
1307 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
1308 content::RecordAction(
1309 UserMetricsAction("Options_DefaultMIDISysExSettingChanged"));
1311 case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
1312 content::RecordAction(
1313 UserMetricsAction("Options_DefaultPushMessagingSettingChanged"));
1320 void ContentSettingsHandler::RemoveException(const base::ListValue* args) {
1321 std::string type_string;
1322 CHECK(args->GetString(0, &type_string));
1324 // Zoom levels are no actual content type so we need to handle them
1325 // separately. They would not be recognized by
1326 // ContentSettingsTypeFromGroupName.
1327 if (type_string == kZoomContentType) {
1328 RemoveZoomLevelException(args);
1332 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
1333 if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM)
1334 RemoveMediaException(args);
1336 RemoveExceptionFromHostContentSettingsMap(args, type);
1339 void ContentSettingsHandler::SetException(const base::ListValue* args) {
1340 std::string type_string;
1341 CHECK(args->GetString(0, &type_string));
1343 CHECK(args->GetString(1, &mode));
1344 std::string pattern;
1345 CHECK(args->GetString(2, &pattern));
1346 std::string setting;
1347 CHECK(args->GetString(3, &setting));
1349 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
1350 if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
1351 type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS ||
1352 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM ||
1353 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
1354 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
1357 HostContentSettingsMap* settings_map =
1358 mode == "normal" ? GetContentSettingsMap() :
1359 GetOTRContentSettingsMap();
1361 // The settings map could be null if the mode was OTR but the OTR profile
1362 // got destroyed before we received this message.
1365 settings_map->SetContentSetting(ContentSettingsPattern::FromString(pattern),
1366 ContentSettingsPattern::Wildcard(),
1369 ContentSettingFromString(setting));
1373 void ContentSettingsHandler::CheckExceptionPatternValidity(
1374 const base::ListValue* args) {
1375 std::string type_string;
1376 CHECK(args->GetString(0, &type_string));
1377 std::string mode_string;
1378 CHECK(args->GetString(1, &mode_string));
1379 std::string pattern_string;
1380 CHECK(args->GetString(2, &pattern_string));
1382 ContentSettingsPattern pattern =
1383 ContentSettingsPattern::FromString(pattern_string);
1385 web_ui()->CallJavascriptFunction(
1386 "ContentSettings.patternValidityCheckComplete",
1387 base::StringValue(type_string),
1388 base::StringValue(mode_string),
1389 base::StringValue(pattern_string),
1390 base::FundamentalValue(pattern.IsValid()));
1394 std::string ContentSettingsHandler::ContentSettingsTypeToGroupName(
1395 ContentSettingsType type) {
1396 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) {
1397 if (type == kContentSettingsTypeGroupNames[i].type)
1398 return kContentSettingsTypeGroupNames[i].name;
1402 return std::string();
1405 HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() {
1406 return Profile::FromWebUI(web_ui())->GetHostContentSettingsMap();
1409 ProtocolHandlerRegistry* ContentSettingsHandler::GetProtocolHandlerRegistry() {
1410 return ProtocolHandlerRegistryFactory::GetForBrowserContext(
1411 GetBrowserContext(web_ui()));
1414 HostContentSettingsMap*
1415 ContentSettingsHandler::GetOTRContentSettingsMap() {
1416 Profile* profile = Profile::FromWebUI(web_ui());
1417 if (profile->HasOffTheRecordProfile())
1418 return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
1422 void ContentSettingsHandler::RefreshFlashMediaSettings() {
1423 media_settings_.flash_settings_initialized = false;
1425 media_settings_.last_flash_refresh_request_id =
1426 flash_settings_manager_->GetPermissionSettings(
1427 PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC);
1430 void ContentSettingsHandler::OnPepperFlashPrefChanged() {
1431 ShowFlashMediaLink(DEFAULT_SETTING, false);
1432 ShowFlashMediaLink(EXCEPTIONS, false);
1434 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
1435 if (prefs->GetBoolean(prefs::kPepperFlashSettingsEnabled))
1436 RefreshFlashMediaSettings();
1438 media_settings_.flash_settings_initialized = false;
1441 void ContentSettingsHandler::OnZoomLevelChanged(
1442 const content::HostZoomMap::ZoomLevelChange& change) {
1443 UpdateZoomLevelsExceptionsView();
1446 void ContentSettingsHandler::ShowFlashMediaLink(LinkType link_type, bool show) {
1447 bool& show_link = link_type == DEFAULT_SETTING ?
1448 media_settings_.show_flash_default_link :
1449 media_settings_.show_flash_exceptions_link;
1450 if (show_link != show) {
1451 web_ui()->CallJavascriptFunction(
1452 link_type == DEFAULT_SETTING ?
1453 "ContentSettings.showMediaPepperFlashDefaultLink" :
1454 "ContentSettings.showMediaPepperFlashExceptionsLink",
1455 base::FundamentalValue(show));
1460 void ContentSettingsHandler::UpdateFlashMediaLinksVisibility() {
1461 if (!media_settings_.flash_settings_initialized ||
1462 !media_settings_.default_setting_initialized ||
1463 !media_settings_.exceptions_initialized) {
1467 // Flash won't send us notifications when its settings get changed, which
1468 // means the Flash settings in |media_settings_| may be out-dated, especially
1469 // after we show links to change Flash settings.
1470 // In order to avoid confusion, we won't hide the links once they are showed.
1471 // One exception is that we will hide them when Pepper Flash is disabled
1472 // (handled in OnPepperFlashPrefChanged()).
1473 if (media_settings_.show_flash_default_link &&
1474 media_settings_.show_flash_exceptions_link) {
1478 if (!media_settings_.show_flash_default_link) {
1479 // If both audio and video capture are disabled by policy, the link
1480 // shouldn't be showed. Flash conforms to the policy in this case because
1481 // it cannot open those devices. We don't have to look at the Flash
1483 if (!(media_settings_.policy_disable_audio &&
1484 media_settings_.policy_disable_video) &&
1485 media_settings_.flash_default_setting !=
1486 media_settings_.default_setting) {
1487 ShowFlashMediaLink(DEFAULT_SETTING, true);
1490 if (!media_settings_.show_flash_exceptions_link) {
1491 // If audio or video capture is disabled by policy, we skip comparison of
1492 // exceptions for audio or video capture, respectively.
1493 if (!PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
1494 media_settings_.default_setting,
1495 media_settings_.exceptions,
1496 media_settings_.flash_default_setting,
1497 media_settings_.flash_exceptions,
1498 media_settings_.policy_disable_audio,
1499 media_settings_.policy_disable_video)) {
1500 ShowFlashMediaLink(EXCEPTIONS, true);
1505 void ContentSettingsHandler::UpdateProtectedContentExceptionsButton() {
1506 #if defined(OS_CHROMEOS)
1507 // Guests cannot modify exceptions. UIAccountTweaks will disabled the button.
1508 if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
1512 // Exceptions apply only when the feature is enabled.
1513 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
1514 bool enable_exceptions = prefs->GetBoolean(prefs::kEnableDRM);
1515 web_ui()->CallJavascriptFunction(
1516 "ContentSettings.enableProtectedContentExceptions",
1517 base::FundamentalValue(enable_exceptions));
1520 } // namespace options