Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / options / content_settings_handler.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/webui/options/content_settings_handler.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/command_line.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/values.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/content_settings/content_settings_details.h"
21 #include "chrome/browser/content_settings/content_settings_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"
53
54 #if defined(OS_CHROMEOS)
55 #include "components/user_manager/user_manager.h"
56 #endif
57
58 using base::UserMetricsAction;
59 using extensions::APIPermission;
60
61 namespace {
62
63 struct ContentSettingsTypeNameEntry {
64   ContentSettingsType type;
65   const char* name;
66 };
67
68 // Maps from a secondary pattern to a setting.
69 typedef std::map<ContentSettingsPattern, ContentSetting>
70     OnePatternSettings;
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>,
74                  OnePatternSettings>
75     AllPatternsSettings;
76
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);
81
82 const char kExceptionsLearnMoreUrl[] =
83     "https://support.google.com/chrome/?p=settings_manage_exceptions";
84
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";
94
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"},
117 #endif
118 };
119
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";
123
124 content::BrowserContext* GetBrowserContext(content::WebUI* web_ui) {
125   return web_ui->GetWebContents()->GetBrowserContext();
126 }
127
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;
132   }
133
134   NOTREACHED() << name << " is not a recognized content settings type.";
135   return CONTENT_SETTINGS_TYPE_DEFAULT;
136 }
137
138 std::string ContentSettingToString(ContentSetting setting) {
139   switch (setting) {
140     case CONTENT_SETTING_ALLOW:
141       return "allow";
142     case CONTENT_SETTING_ASK:
143       return "ask";
144     case CONTENT_SETTING_BLOCK:
145       return "block";
146     case CONTENT_SETTING_SESSION_ONLY:
147       return "session";
148     case CONTENT_SETTING_DEFAULT:
149       return "default";
150     case CONTENT_SETTING_NUM_SETTINGS:
151       NOTREACHED();
152   }
153
154   return std::string();
155 }
156
157 ContentSetting ContentSettingFromString(const std::string& name) {
158   if (name == "allow")
159     return CONTENT_SETTING_ALLOW;
160   if (name == "ask")
161     return CONTENT_SETTING_ASK;
162   if (name == "block")
163     return CONTENT_SETTING_BLOCK;
164   if (name == "session")
165     return CONTENT_SETTING_SESSION_ONLY;
166
167   NOTREACHED() << name << " is not a recognized content setting.";
168   return CONTENT_SETTING_DEFAULT;
169 }
170
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() ?
183                            std::string() :
184                            secondary_pattern.ToString());
185   exception->SetString(kSetting, ContentSettingToString(setting));
186   exception->SetString(kSource, provider_name);
187   return exception;
188 }
189
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
192 // the caller.
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());
201   return exception;
202 }
203
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);
215   return exception;
216 }
217
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);
225 }
226
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);
239 }
240
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))
251       continue;
252
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);
259     }
260     // Retrieve the launch URL.
261     GURL 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))
265       continue;
266     AddExceptionForHostedApp(launch_url.spec(), *extension->get(), exceptions);
267   }
268 }
269
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;
275 }
276
277 }  // namespace
278
279 namespace options {
280
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) {
292 }
293
294 ContentSettingsHandler::MediaSettingsInfo::~MediaSettingsInfo() {
295 }
296
297 ContentSettingsHandler::ContentSettingsHandler() {
298 }
299
300 ContentSettingsHandler::~ContentSettingsHandler() {
301 }
302
303 void ContentSettingsHandler::GetLocalizedValues(
304     base::DictionaryValue* localized_strings) {
305   DCHECK(localized_strings);
306
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 },
320     // Cookies filter.
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 },
335 #endif
336     // Image filter.
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 },
346     // Plug-ins filter.
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 },
353     // Pop-ups filter.
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 },
358     // Location filter.
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 },
434   };
435
436   RegisterStrings(localized_strings, resources, arraysize(resources));
437   RegisterTitle(localized_strings, "contentSettingsPage",
438                 IDS_CONTENT_SETTINGS_TITLE);
439
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);
463 #endif
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);
474
475   localized_strings->SetString("exceptionsLearnMoreUrl",
476                                kExceptionsLearnMoreUrl);
477 }
478
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());
486
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));
497
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(
513       prefs::kEnableDRM,
514       base::Bind(
515           &ContentSettingsHandler::UpdateProtectedContentExceptionsButton,
516           base::Unretained(this)));
517
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)));
524
525   flash_settings_manager_.reset(new PepperFlashSettingsManager(this, context));
526 }
527
528 void ContentSettingsHandler::InitializePage() {
529   media_settings_ = MediaSettingsInfo();
530   RefreshFlashMediaSettings();
531
532   UpdateHandlersEnabledRadios();
533   UpdateAllExceptionsViewsFromModel();
534   UpdateProtectedContentExceptionsButton();
535 }
536
537 void ContentSettingsHandler::Observe(
538     int type,
539     const content::NotificationSource& source,
540     const content::NotificationDetails& details) {
541   switch (type) {
542     case chrome::NOTIFICATION_PROFILE_DESTROYED: {
543       if (content::Source<Profile>(source).ptr()->IsOffTheRecord()) {
544         web_ui()->CallJavascriptFunction(
545             "ContentSettingsExceptionsArea.OTRProfileDestroyed");
546       }
547       break;
548     }
549
550     case chrome::NOTIFICATION_PROFILE_CREATED: {
551       if (content::Source<Profile>(source).ptr()->IsOffTheRecord())
552         UpdateAllOTRExceptionsViewsFromModel();
553       break;
554     }
555
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())
562         break;
563
564       const ContentSettingsDetails* settings_details =
565           content::Details<const ContentSettingsDetails>(details).ptr();
566
567       // TODO(estade): we pretend update_all() is always true.
568       if (settings_details->update_all_types())
569         UpdateAllExceptionsViewsFromModel();
570       else
571         UpdateExceptionsViewFromModel(settings_details->type());
572       break;
573     }
574
575     case chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED: {
576       UpdateNotificationExceptionsView();
577       break;
578     }
579
580     case chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED: {
581       UpdateHandlersEnabledRadios();
582       break;
583     }
584   }
585 }
586
587 void ContentSettingsHandler::OnGetPermissionSettingsCompleted(
588     uint32 request_id,
589     bool success,
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(
596             default_permission);
597     PepperFlashContentSettingsUtils::FlashSiteSettingsToMediaExceptions(
598         sites, &media_settings_.flash_exceptions);
599     PepperFlashContentSettingsUtils::SortMediaExceptions(
600         &media_settings_.flash_exceptions);
601
602     UpdateFlashMediaLinksVisibility();
603   }
604 }
605
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);
614
615   web_ui()->CallJavascriptFunction(
616       "ContentSettings.setContentFilterSettingsValue", filter_settings);
617 }
618
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);
625
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();
633
634   base::DictionaryValue media_ui_settings;
635   media_ui_settings.SetBoolean("cameraDisabled", video_disabled);
636   media_ui_settings.SetBoolean("micDisabled", audio_disabled);
637
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");
644
645     web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
646                                      media_ui_settings);
647     return;
648   }
649
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");
657
658     web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
659                                      media_ui_settings);
660     return;
661   }
662
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);
674   }
675
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());
680
681   web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
682                                    media_ui_settings);
683 }
684
685 std::string ContentSettingsHandler::GetSettingDefaultFromModel(
686     ContentSettingsType type, std::string* provider_id) {
687   Profile* profile = Profile::FromWebUI(web_ui());
688   ContentSetting default_setting;
689   default_setting =
690       profile->GetHostContentSettingsMap()->GetDefaultContentSetting(
691           type, provider_id);
692
693   return ContentSettingToString(default_setting);
694 }
695
696 void ContentSettingsHandler::UpdateHandlersEnabledRadios() {
697   base::FundamentalValue handlers_enabled(
698       GetProtocolHandlerRegistry()->enabled());
699
700   web_ui()->CallJavascriptFunction(
701       "ContentSettings.updateHandlersEnabledRadios",
702       handlers_enabled);
703 }
704
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));
709   }
710   // Zoom levels are not actually a content type so we need to handle them
711   // separately.
712   UpdateZoomLevelsExceptionsView();
713 }
714
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));
719   }
720 }
721
722 void ContentSettingsHandler::UpdateExceptionsViewFromModel(
723     ContentSettingsType type) {
724   switch (type) {
725     case CONTENT_SETTINGS_TYPE_GEOLOCATION:
726       UpdateGeolocationExceptionsView();
727       break;
728     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
729       UpdateNotificationExceptionsView();
730       break;
731     case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
732       UpdateMediaSettingsView();
733       break;
734     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
735     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
736       UpdateMediaExceptionsView();
737       break;
738     case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
739       // We don't yet support exceptions for mixed scripting.
740       break;
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.
745       break;
746     case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS:
747       // The RPH settings are retrieved separately.
748       break;
749     case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
750       UpdateMIDISysExExceptionsView();
751       break;
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.
756       break;
757 #if defined(OS_WIN)
758     case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
759       break;
760 #endif
761     default:
762       UpdateExceptionsViewFromHostContentSettingsMap(type);
763       break;
764   }
765 }
766
767 void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel(
768     ContentSettingsType type) {
769   switch (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:
774 #if defined(OS_WIN)
775     case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
776 #endif
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:
783       break;
784     default:
785       UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
786       break;
787   }
788 }
789
790 // TODO(estade): merge with GetExceptionsFromHostContentSettingsMap.
791 void ContentSettingsHandler::UpdateGeolocationExceptionsView() {
792   Profile* profile = Profile::FromWebUI(web_ui());
793   HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
794
795   ContentSettingsForOneType all_settings;
796   map->GetSettingsForOneType(
797       CONTENT_SETTINGS_TYPE_GEOLOCATION,
798       std::string(),
799       &all_settings);
800
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) {
809       continue;
810     }
811     all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
812         [i->secondary_pattern] = i->setting;
813   }
814
815   base::ListValue exceptions;
816   AddExceptionsGrantedByHostedApps(
817       profile,
818       HostedAppHasPermission<APIPermission::kGeolocation>,
819       &exceptions);
820
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;
825
826     OnePatternSettings::const_iterator parent =
827         one_settings.find(primary_pattern);
828
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,
833                                                      primary_pattern,
834                                                      parent_setting));
835
836     // Add the "children" for any embedded settings.
837     for (OnePatternSettings::const_iterator j = one_settings.begin();
838          j != one_settings.end();
839          ++j) {
840       // Skip the non-embedded setting which we already added above.
841       if (j == parent)
842         continue;
843
844       exceptions.Append(GetGeolocationExceptionForPage(
845           primary_pattern, j->first, j->second));
846     }
847   }
848
849   base::StringValue type_string(
850       ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION));
851   web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
852                                    type_string, exceptions);
853
854   // This is mainly here to keep this function ideologically parallel to
855   // UpdateExceptionsViewFromHostContentSettingsMap().
856   UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION);
857 }
858
859 void ContentSettingsHandler::UpdateNotificationExceptionsView() {
860   Profile* profile = Profile::FromWebUI(web_ui());
861   ContentSettingsForOneType settings;
862   DesktopNotificationProfileUtil::GetNotificationsSettings(profile, &settings);
863
864   base::ListValue exceptions;
865   AddExceptionsGrantedByHostedApps(
866       profile,
867       HostedAppHasPermission<APIPermission::kNotifications>,
868       &exceptions);
869
870   for (ContentSettingsForOneType::const_iterator i =
871            settings.begin();
872        i != settings.end();
873        ++i) {
874     // Don't add default settings.
875     if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
876         i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
877         i->source != kPreferencesSource) {
878       continue;
879     }
880
881     exceptions.Append(
882         GetNotificationExceptionForPage(i->primary_pattern, i->setting,
883                                         i->source));
884   }
885
886   base::StringValue type_string(
887       ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
888   web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
889                                    type_string, exceptions);
890
891   // This is mainly here to keep this function ideologically parallel to
892   // UpdateExceptionsViewFromHostContentSettingsMap().
893   UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
894 }
895
896 void ContentSettingsHandler::UpdateMediaExceptionsView() {
897   base::ListValue media_exceptions;
898   GetExceptionsFromHostContentSettingsMap(
899       GetContentSettingsMap(),
900       CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
901       &media_exceptions);
902
903   base::ListValue video_exceptions;
904   GetExceptionsFromHostContentSettingsMap(
905       GetContentSettingsMap(),
906       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
907       &video_exceptions);
908
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))
915       NOTREACHED();
916
917     media_dict->SetString(kVideoSetting,
918                           ContentSettingToString(CONTENT_SETTING_ASK));
919
920     std::string media_origin;
921     media_dict->GetString(kOrigin, &media_origin);
922     entries_map[media_origin] = media_dict;
923   }
924
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))
929       NOTREACHED();
930
931     std::string video_origin;
932     std::string video_setting;
933     video_dict->GetString(kOrigin, &video_origin);
934     video_dict->GetString(kSetting, &video_setting);
935
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);
945
946       // Append the new entry to the list and map.
947       media_exceptions.Append(exception);
948       entries_map[video_origin] = exception;
949     } else {
950       // Modify the existing entry.
951       iter->second->SetString(kVideoSetting, video_setting);
952     }
953   }
954
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);
960     DCHECK(result);
961
962     std::string origin;
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)));
972   }
973   PepperFlashContentSettingsUtils::SortMediaExceptions(
974       &media_settings_.exceptions);
975   media_settings_.exceptions_initialized = true;
976   UpdateFlashMediaLinksVisibility();
977
978   base::StringValue type_string(
979        ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM));
980   web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
981                                    type_string, media_exceptions);
982
983   UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
984 }
985
986 void ContentSettingsHandler::UpdateMIDISysExExceptionsView() {
987   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebMIDI)) {
988     web_ui()->CallJavascriptFunction(
989         "ContentSettings.showExperimentalWebMIDISettings",
990         base::FundamentalValue(true));
991   }
992
993   UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
994   UpdateExceptionsViewFromHostContentSettingsMap(
995       CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
996 }
997
998 void ContentSettingsHandler::UpdateZoomLevelsExceptionsView() {
999   base::ListValue zoom_levels_exceptions;
1000
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);
1006
1007   for (content::HostZoomMap::ZoomLevelVector::const_iterator i =
1008            zoom_levels.begin();
1009        i != zoom_levels.end();
1010        ++i) {
1011     scoped_ptr<base::DictionaryValue> exception(new base::DictionaryValue);
1012     switch (i->mode) {
1013       case content::HostZoomMap::ZOOM_CHANGED_FOR_HOST:
1014         exception->SetString(kOrigin, i->host);
1015         break;
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.
1019         break;
1020       case content::HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM:
1021         NOTREACHED();
1022     }
1023     exception->SetString(kSetting,
1024                          ContentSettingToString(CONTENT_SETTING_DEFAULT));
1025
1026     // Calculate the zoom percent from the factor. Round up to the nearest whole
1027     // number.
1028     int zoom_percent = static_cast<int>(
1029         content::ZoomLevelToZoomFactor(i->zoom_level) * 100 + 0.5);
1030     exception->SetString(
1031         kZoom,
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());
1037   }
1038
1039   base::StringValue type_string(kZoomContentType);
1040   web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
1041                                    type_string, zoom_levels_exceptions);
1042 }
1043
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,
1051                                    exceptions);
1052
1053   UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
1054
1055   // TODO(koz): The default for fullscreen is always 'ask'.
1056   // http://crbug.com/104683
1057   if (type == CONTENT_SETTINGS_TYPE_FULLSCREEN)
1058     return;
1059
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)
1063     return;
1064 #endif
1065
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);
1069 }
1070
1071 void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap(
1072     ContentSettingsType type) {
1073   const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap();
1074   if (!otr_settings_map)
1075     return;
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);
1081 }
1082
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) {
1097       continue;
1098     }
1099
1100     // Off-the-record HostContentSettingsMap contains incognito content settings
1101     // as well as normal content settings. Here, we use the incongnito settings
1102     // only.
1103     if (map->is_off_the_record() && !i->incognito)
1104       continue;
1105
1106     all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
1107         [i->secondary_pattern] = i->setting;
1108   }
1109
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);
1114
1115   for (AllPatternsSettings::iterator i = all_patterns_settings.begin();
1116        i != all_patterns_settings.end();
1117        ++i) {
1118     const ContentSettingsPattern& primary_pattern = i->first.first;
1119     const OnePatternSettings& one_settings = i->second;
1120
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
1123     // UI.
1124     OnePatternSettings::const_iterator parent =
1125         one_settings.find(primary_pattern);
1126     if (parent == one_settings.end())
1127       parent = one_settings.find(ContentSettingsPattern::Wildcard());
1128
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));
1133
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,
1140                                                             secondary_pattern,
1141                                                             parent_setting,
1142                                                             source));
1143
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.
1148       if (j == parent)
1149         continue;
1150
1151       ContentSetting content_setting = j->second;
1152       this_provider_exceptions->push_back(GetExceptionForPage(
1153           primary_pattern,
1154           j->first,
1155           content_setting,
1156           source));
1157     }
1158   }
1159
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]);
1163     }
1164   }
1165 }
1166
1167 void ContentSettingsHandler::RemoveNotificationException(
1168     const base::ListValue* args) {
1169   Profile* profile = Profile::FromWebUI(web_ui());
1170
1171   std::string origin;
1172   std::string setting;
1173   bool rv = args->GetString(1, &origin);
1174   DCHECK(rv);
1175   rv = args->GetString(2, &setting);
1176   DCHECK(rv);
1177   ContentSetting content_setting = ContentSettingFromString(setting);
1178
1179   DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
1180          content_setting == CONTENT_SETTING_BLOCK);
1181   DesktopNotificationProfileUtil::ClearSetting(profile,
1182       ContentSettingsPattern::FromString(origin));
1183 }
1184
1185 void ContentSettingsHandler::RemoveMediaException(const base::ListValue* args) {
1186   std::string mode;
1187   bool rv = args->GetString(1, &mode);
1188   DCHECK(rv);
1189
1190   std::string pattern;
1191   rv = args->GetString(2, &pattern);
1192   DCHECK(rv);
1193
1194   HostContentSettingsMap* settings_map =
1195       mode == "normal" ? GetContentSettingsMap() :
1196                          GetOTRContentSettingsMap();
1197   if (settings_map) {
1198     settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1199                                     ContentSettingsPattern::Wildcard(),
1200                                     CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
1201                                     std::string(),
1202                                     NULL);
1203     settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1204                                     ContentSettingsPattern::Wildcard(),
1205                                     CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
1206                                     std::string(),
1207                                     NULL);
1208   }
1209 }
1210
1211 void ContentSettingsHandler::RemoveExceptionFromHostContentSettingsMap(
1212     const base::ListValue* args,
1213     ContentSettingsType type) {
1214   std::string mode;
1215   bool rv = args->GetString(1, &mode);
1216   DCHECK(rv);
1217
1218   std::string pattern;
1219   rv = args->GetString(2, &pattern);
1220   DCHECK(rv);
1221
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);
1226     DCHECK(rv);
1227   }
1228
1229   HostContentSettingsMap* settings_map =
1230       mode == "normal" ? GetContentSettingsMap() :
1231                          GetOTRContentSettingsMap();
1232   if (settings_map) {
1233     settings_map->SetWebsiteSetting(
1234         ContentSettingsPattern::FromString(pattern),
1235         secondary_pattern.empty() ?
1236             ContentSettingsPattern::Wildcard() :
1237             ContentSettingsPattern::FromString(secondary_pattern),
1238         type,
1239         std::string(),
1240         NULL);
1241   }
1242 }
1243
1244 void ContentSettingsHandler::RemoveZoomLevelException(
1245     const base::ListValue* args) {
1246   std::string mode;
1247   bool rv = args->GetString(1, &mode);
1248   DCHECK(rv);
1249
1250   std::string pattern;
1251   rv = args->GetString(2, &pattern);
1252   DCHECK(rv);
1253
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);
1258 }
1259
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)));
1273 }
1274
1275 void ContentSettingsHandler::ApplyWhitelist(ContentSettingsType content_type,
1276                                             ContentSetting default_setting) {
1277   HostContentSettingsMap* map = GetContentSettingsMap();
1278   if (content_type != CONTENT_SETTINGS_TYPE_PLUGINS)
1279     return;
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)
1285     return;
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,
1296         "google-talk",
1297         new base::FundamentalValue(CONTENT_SETTING_ALLOW));
1298   }
1299   prefs->SetInteger(prefs::kContentSettingsDefaultWhitelistVersion,
1300                     kDefaultWhitelistVersion);
1301 }
1302
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))) {
1308     NOTREACHED();
1309     return;
1310   }
1311
1312   ContentSetting default_setting = ContentSettingFromString(setting);
1313   ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group);
1314   Profile* profile = Profile::FromWebUI(web_ui());
1315
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();
1321 #endif
1322
1323
1324   HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
1325   ApplyWhitelist(content_type, default_setting);
1326   map->SetDefaultContentSetting(content_type, default_setting);
1327
1328   switch (content_type) {
1329     case CONTENT_SETTINGS_TYPE_COOKIES:
1330       content::RecordAction(
1331           UserMetricsAction("Options_DefaultCookieSettingChanged"));
1332       break;
1333     case CONTENT_SETTINGS_TYPE_IMAGES:
1334       content::RecordAction(
1335           UserMetricsAction("Options_DefaultImagesSettingChanged"));
1336       break;
1337     case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
1338       content::RecordAction(
1339           UserMetricsAction("Options_DefaultJavaScriptSettingChanged"));
1340       break;
1341     case CONTENT_SETTINGS_TYPE_PLUGINS:
1342       content::RecordAction(
1343           UserMetricsAction("Options_DefaultPluginsSettingChanged"));
1344       break;
1345     case CONTENT_SETTINGS_TYPE_POPUPS:
1346       content::RecordAction(
1347           UserMetricsAction("Options_DefaultPopupsSettingChanged"));
1348       break;
1349     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
1350       content::RecordAction(
1351           UserMetricsAction("Options_DefaultNotificationsSettingChanged"));
1352       break;
1353     case CONTENT_SETTINGS_TYPE_GEOLOCATION:
1354       content::RecordAction(
1355           UserMetricsAction("Options_DefaultGeolocationSettingChanged"));
1356       break;
1357     case CONTENT_SETTINGS_TYPE_MOUSELOCK:
1358       content::RecordAction(
1359           UserMetricsAction("Options_DefaultMouseLockSettingChanged"));
1360       break;
1361     case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
1362       content::RecordAction(
1363           UserMetricsAction("Options_DefaultMediaStreamMicSettingChanged"));
1364       break;
1365     case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
1366       content::RecordAction(
1367           UserMetricsAction("Options_DefaultMultipleAutomaticDLSettingChange"));
1368       break;
1369     case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
1370       content::RecordAction(
1371           UserMetricsAction("Options_DefaultMIDISysExSettingChanged"));
1372       break;
1373     case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
1374       content::RecordAction(
1375           UserMetricsAction("Options_DefaultPushMessagingSettingChanged"));
1376       break;
1377     default:
1378       break;
1379   }
1380 }
1381
1382 void ContentSettingsHandler::RemoveException(const base::ListValue* args) {
1383   std::string type_string;
1384   CHECK(args->GetString(0, &type_string));
1385
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);
1391     return;
1392   }
1393
1394   ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
1395   switch (type) {
1396     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
1397       RemoveNotificationException(args);
1398       break;
1399     case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
1400       RemoveMediaException(args);
1401       break;
1402     default:
1403       RemoveExceptionFromHostContentSettingsMap(args, type);
1404       break;
1405   }
1406 }
1407
1408 void ContentSettingsHandler::SetException(const base::ListValue* args) {
1409   std::string type_string;
1410   CHECK(args->GetString(0, &type_string));
1411   std::string mode;
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));
1417
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) {
1424     NOTREACHED();
1425   } else {
1426     HostContentSettingsMap* settings_map =
1427         mode == "normal" ? GetContentSettingsMap() :
1428                            GetOTRContentSettingsMap();
1429
1430     // The settings map could be null if the mode was OTR but the OTR profile
1431     // got destroyed before we received this message.
1432     if (!settings_map)
1433       return;
1434     settings_map->SetContentSetting(ContentSettingsPattern::FromString(pattern),
1435                                     ContentSettingsPattern::Wildcard(),
1436                                     type,
1437                                     std::string(),
1438                                     ContentSettingFromString(setting));
1439   }
1440 }
1441
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));
1450
1451   ContentSettingsPattern pattern =
1452       ContentSettingsPattern::FromString(pattern_string);
1453
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()));
1460 }
1461
1462 // static
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;
1468   }
1469
1470   NOTREACHED();
1471   return std::string();
1472 }
1473
1474 HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() {
1475   return Profile::FromWebUI(web_ui())->GetHostContentSettingsMap();
1476 }
1477
1478 ProtocolHandlerRegistry* ContentSettingsHandler::GetProtocolHandlerRegistry() {
1479   return ProtocolHandlerRegistryFactory::GetForBrowserContext(
1480       GetBrowserContext(web_ui()));
1481 }
1482
1483 HostContentSettingsMap*
1484     ContentSettingsHandler::GetOTRContentSettingsMap() {
1485   Profile* profile = Profile::FromWebUI(web_ui());
1486   if (profile->HasOffTheRecordProfile())
1487     return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
1488   return NULL;
1489 }
1490
1491 void ContentSettingsHandler::RefreshFlashMediaSettings() {
1492   media_settings_.flash_settings_initialized = false;
1493
1494   media_settings_.last_flash_refresh_request_id =
1495       flash_settings_manager_->GetPermissionSettings(
1496           PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC);
1497 }
1498
1499 void ContentSettingsHandler::OnPepperFlashPrefChanged() {
1500   ShowFlashMediaLink(DEFAULT_SETTING, false);
1501   ShowFlashMediaLink(EXCEPTIONS, false);
1502
1503   PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
1504   if (prefs->GetBoolean(prefs::kPepperFlashSettingsEnabled))
1505     RefreshFlashMediaSettings();
1506   else
1507     media_settings_.flash_settings_initialized = false;
1508 }
1509
1510 void ContentSettingsHandler::OnZoomLevelChanged(
1511     const content::HostZoomMap::ZoomLevelChange& change) {
1512   UpdateZoomLevelsExceptionsView();
1513 }
1514
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));
1525     show_link = show;
1526   }
1527 }
1528
1529 void ContentSettingsHandler::UpdateFlashMediaLinksVisibility() {
1530   if (!media_settings_.flash_settings_initialized ||
1531       !media_settings_.default_setting_initialized ||
1532       !media_settings_.exceptions_initialized) {
1533     return;
1534   }
1535
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) {
1544     return;
1545   }
1546
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
1551     // settings.
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);
1557     }
1558   }
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);
1570     }
1571   }
1572 }
1573
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));
1581 }
1582
1583 }  // namespace options