Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / content_settings / content_setting_bubble_model.cc
blob1eb9c754343c1cc375ea9670b298e854ceb8035b
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/content_settings/content_setting_bubble_model.h"
7 #include "base/command_line.h"
8 #include "base/macros.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/stl_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/content_settings/chrome_content_settings_utils.h"
14 #include "chrome/browser/content_settings/cookie_settings_factory.h"
15 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
16 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
17 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
18 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
19 #include "chrome/browser/infobars/infobar_service.h"
20 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
21 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
24 #include "chrome/browser/ui/browser_navigator.h"
25 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
26 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/common/render_messages.h"
30 #include "chrome/grit/generated_resources.h"
31 #include "components/content_settings/content/common/content_settings_messages.h"
32 #include "components/content_settings/core/browser/content_settings_utils.h"
33 #include "components/content_settings/core/browser/cookie_settings.h"
34 #include "components/content_settings/core/common/content_settings.h"
35 #include "components/url_formatter/elide_url.h"
36 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/render_frame_host.h"
38 #include "content/public/browser/render_process_host.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/user_metrics.h"
41 #include "content/public/browser/web_contents.h"
42 #include "content/public/browser/web_contents_delegate.h"
43 #include "content/public/common/origin_util.h"
44 #include "grit/components_strings.h"
45 #include "grit/theme_resources.h"
46 #include "ui/base/l10n/l10n_util.h"
47 #include "ui/base/resource/resource_bundle.h"
48 #include "ui/resources/grit/ui_resources.h"
50 using base::UserMetricsAction;
51 using content::WebContents;
52 using content_settings::SettingInfo;
53 using content_settings::SettingSource;
54 using content_settings::SETTING_SOURCE_USER;
55 using content_settings::SETTING_SOURCE_NONE;
57 namespace {
59 const int kAllowButtonIndex = 0;
61 // static
62 const ContentSettingsType kSupportedBubbleTypes[] = {
63 CONTENT_SETTINGS_TYPE_COOKIES,
64 CONTENT_SETTINGS_TYPE_IMAGES,
65 CONTENT_SETTINGS_TYPE_JAVASCRIPT,
66 CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
67 CONTENT_SETTINGS_TYPE_PLUGINS,
68 CONTENT_SETTINGS_TYPE_POPUPS,
69 CONTENT_SETTINGS_TYPE_GEOLOCATION,
70 CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
71 CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS,
72 CONTENT_SETTINGS_TYPE_MEDIASTREAM,
73 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
74 CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
77 // These states must match the order of appearance of the radio buttons
78 // in the XIB file for the Mac port.
79 enum RPHState {
80 RPH_ALLOW = 0,
81 RPH_BLOCK,
82 RPH_IGNORE,
85 struct ContentSettingsTypeIdEntry {
86 ContentSettingsType type;
87 int id;
90 int GetIdForContentType(const ContentSettingsTypeIdEntry* entries,
91 size_t num_entries,
92 ContentSettingsType type) {
93 for (size_t i = 0; i < num_entries; ++i) {
94 if (entries[i].type == type)
95 return entries[i].id;
97 return 0;
100 const content::MediaStreamDevice& GetMediaDeviceById(
101 const std::string& device_id,
102 const content::MediaStreamDevices& devices) {
103 DCHECK(!devices.empty());
104 for (const content::MediaStreamDevice& device : devices) {
105 if (device.id == device_id)
106 return device;
109 // A device with the |device_id| was not found. It is likely that the device
110 // has been unplugged from the OS. Return the first device as the default
111 // device.
112 return *devices.begin();
115 } // namespace
117 ContentSettingTitleAndLinkModel::ContentSettingTitleAndLinkModel(
118 Delegate* delegate,
119 WebContents* web_contents,
120 Profile* profile,
121 ContentSettingsType content_type)
122 : ContentSettingBubbleModel(web_contents, profile, content_type),
123 delegate_(delegate) {
124 // Notifications do not have a bubble.
125 DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
126 SetTitle();
127 SetManageLink();
128 SetLearnMoreLink();
131 void ContentSettingTitleAndLinkModel::SetTitle() {
132 TabSpecificContentSettings* content_settings = NULL;
133 if (web_contents()) {
134 content_settings =
135 TabSpecificContentSettings::FromWebContents(web_contents());
138 static const ContentSettingsTypeIdEntry kBlockedTitleIDs[] = {
139 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE},
140 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE},
141 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE},
142 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_TITLE},
143 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TITLE},
144 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
145 IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT},
146 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
147 IDS_BLOCKED_PPAPI_BROKER_TITLE},
148 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_TITLE},
150 // Fields as for kBlockedTitleIDs, above.
151 static const ContentSettingsTypeIdEntry kAccessedTitleIDs[] = {
152 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_TITLE},
153 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_TITLE},
154 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_TITLE},
156 const ContentSettingsTypeIdEntry *title_ids = kBlockedTitleIDs;
157 size_t num_title_ids = arraysize(kBlockedTitleIDs);
158 if (content_settings && content_settings->IsContentAllowed(content_type()) &&
159 !content_settings->IsContentBlocked(content_type())) {
160 title_ids = kAccessedTitleIDs;
161 num_title_ids = arraysize(kAccessedTitleIDs);
163 int title_id =
164 GetIdForContentType(title_ids, num_title_ids, content_type());
165 if (title_id)
166 set_title(l10n_util::GetStringUTF8(title_id));
169 void ContentSettingTitleAndLinkModel::SetManageLink() {
170 static const ContentSettingsTypeIdEntry kLinkIDs[] = {
171 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_LINK},
172 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_LINK},
173 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_LINK},
174 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LINK},
175 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_LINK},
176 {CONTENT_SETTINGS_TYPE_GEOLOCATION, IDS_GEOLOCATION_BUBBLE_MANAGE_LINK},
177 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_LEARN_MORE},
178 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, IDS_HANDLERS_BUBBLE_MANAGE_LINK},
179 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, IDS_MEDIASTREAM_BUBBLE_MANAGE_LINK},
180 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_PPAPI_BROKER_BUBBLE_MANAGE_LINK},
181 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOADS_LINK},
182 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, IDS_MIDI_SYSEX_BUBBLE_MANAGE_LINK},
184 set_manage_link(l10n_util::GetStringUTF8(
185 GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type())));
188 void ContentSettingTitleAndLinkModel::OnManageLinkClicked() {
189 if (delegate_)
190 delegate_->ShowContentSettingsPage(content_type());
193 void ContentSettingTitleAndLinkModel::SetLearnMoreLink() {
194 static const ContentSettingsTypeIdEntry kLearnMoreIDs[] = {
195 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_LEARN_MORE},
197 int learn_more_id =
198 GetIdForContentType(kLearnMoreIDs, arraysize(kLearnMoreIDs),
199 content_type());
200 if (learn_more_id)
201 set_learn_more_link(l10n_util::GetStringUTF8(learn_more_id));
204 void ContentSettingTitleAndLinkModel::OnLearnMoreLinkClicked() {
205 if (delegate_)
206 delegate_->ShowLearnMorePage(content_type());
209 class ContentSettingTitleLinkAndCustomModel
210 : public ContentSettingTitleAndLinkModel {
211 public:
212 ContentSettingTitleLinkAndCustomModel(Delegate* delegate,
213 WebContents* web_contents,
214 Profile* profile,
215 ContentSettingsType content_type);
216 ~ContentSettingTitleLinkAndCustomModel() override {}
218 private:
219 void SetCustomLink();
220 void OnCustomLinkClicked() override {}
223 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel(
224 Delegate* delegate,
225 WebContents* web_contents,
226 Profile* profile,
227 ContentSettingsType content_type)
228 : ContentSettingTitleAndLinkModel(
229 delegate, web_contents, profile, content_type) {
230 SetCustomLink();
233 void ContentSettingTitleLinkAndCustomModel::SetCustomLink() {
234 static const ContentSettingsTypeIdEntry kCustomIDs[] = {
235 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO},
236 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL},
237 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_ALLOW_INSECURE_CONTENT_BUTTON},
239 int custom_link_id =
240 GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type());
241 if (custom_link_id)
242 set_custom_link(l10n_util::GetStringUTF8(custom_link_id));
245 class ContentSettingSingleRadioGroup
246 : public ContentSettingTitleLinkAndCustomModel {
247 public:
248 ContentSettingSingleRadioGroup(Delegate* delegate,
249 WebContents* web_contents,
250 Profile* profile,
251 ContentSettingsType content_type);
252 ~ContentSettingSingleRadioGroup() override;
254 protected:
255 bool settings_changed() const;
256 int selected_item() const { return selected_item_; }
258 private:
259 void SetRadioGroup();
260 void AddException(ContentSetting setting);
261 void OnRadioClicked(int radio_index) override;
263 ContentSetting block_setting_;
264 int selected_item_;
267 ContentSettingSingleRadioGroup::ContentSettingSingleRadioGroup(
268 Delegate* delegate,
269 WebContents* web_contents,
270 Profile* profile,
271 ContentSettingsType content_type)
272 : ContentSettingTitleLinkAndCustomModel(delegate, web_contents, profile,
273 content_type),
274 block_setting_(CONTENT_SETTING_BLOCK),
275 selected_item_(0) {
276 SetRadioGroup();
279 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() {
280 if (settings_changed()) {
281 ContentSetting setting =
282 selected_item_ == kAllowButtonIndex ?
283 CONTENT_SETTING_ALLOW :
284 block_setting_;
285 AddException(setting);
289 bool ContentSettingSingleRadioGroup::settings_changed() const {
290 return selected_item_ != bubble_content().radio_group.default_item;
293 // Initialize the radio group by setting the appropriate labels for the
294 // content type and setting the default value based on the content setting.
295 void ContentSettingSingleRadioGroup::SetRadioGroup() {
296 GURL url = web_contents()->GetURL();
297 base::string16 display_host = url_formatter::FormatUrlForSecurityDisplay(
298 url, profile()->GetPrefs()->GetString(prefs::kAcceptLanguages));
299 if (display_host.empty())
300 display_host = base::ASCIIToUTF16(url.spec());
302 TabSpecificContentSettings* content_settings =
303 TabSpecificContentSettings::FromWebContents(web_contents());
304 bool allowed =
305 !content_settings->IsContentBlocked(content_type());
306 DCHECK(!allowed ||
307 content_settings->IsContentAllowed(content_type()));
309 RadioGroup radio_group;
310 radio_group.url = url;
312 static const ContentSettingsTypeIdEntry kBlockedAllowIDs[] = {
313 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK},
314 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_UNBLOCK},
315 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_UNBLOCK},
316 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_UNBLOCK_ALL},
317 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_UNBLOCK},
318 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_UNBLOCK},
319 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_UNBLOCK},
321 // Fields as for kBlockedAllowIDs, above.
322 static const ContentSettingsTypeIdEntry kAllowedAllowIDs[] = {
323 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ALLOWED_COOKIES_NO_ACTION},
324 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_NO_ACTION},
325 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_NO_ACTION},
328 std::string radio_allow_label;
329 if (allowed) {
330 int resource_id = GetIdForContentType(kAllowedAllowIDs,
331 arraysize(kAllowedAllowIDs),
332 content_type());
333 radio_allow_label = l10n_util::GetStringUTF8(resource_id);
334 } else {
335 radio_allow_label = l10n_util::GetStringFUTF8(
336 GetIdForContentType(kBlockedAllowIDs, arraysize(kBlockedAllowIDs),
337 content_type()),
338 display_host);
341 static const ContentSettingsTypeIdEntry kBlockedBlockIDs[] = {
342 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION},
343 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_NO_ACTION},
344 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_NO_ACTION},
345 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_NO_ACTION},
346 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_NO_ACTION},
347 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_NO_ACTION},
348 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_NO_ACTION},
350 static const ContentSettingsTypeIdEntry kAllowedBlockIDs[] = {
351 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ALLOWED_COOKIES_BLOCK},
352 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_BLOCK},
353 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_BLOCK},
356 std::string radio_block_label;
357 if (allowed) {
358 int resource_id = GetIdForContentType(kAllowedBlockIDs,
359 arraysize(kAllowedBlockIDs),
360 content_type());
361 radio_block_label = l10n_util::GetStringFUTF8(resource_id, display_host);
362 } else {
363 radio_block_label = l10n_util::GetStringUTF8(
364 GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs),
365 content_type()));
368 radio_group.radio_items.push_back(radio_allow_label);
369 radio_group.radio_items.push_back(radio_block_label);
370 ContentSetting setting;
371 SettingSource setting_source = SETTING_SOURCE_NONE;
372 bool setting_is_wildcard = false;
374 if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) {
375 content_settings::CookieSettings* cookie_settings =
376 CookieSettingsFactory::GetForProfile(profile()).get();
377 setting = cookie_settings->GetCookieSetting(
378 url, url, true, &setting_source);
379 } else {
380 SettingInfo info;
381 HostContentSettingsMap* map =
382 HostContentSettingsMapFactory::GetForProfile(profile());
383 scoped_ptr<base::Value> value =
384 map->GetWebsiteSetting(url, url, content_type(), std::string(), &info);
385 setting = content_settings::ValueToContentSetting(value.get());
386 setting_source = info.source;
387 setting_is_wildcard =
388 info.primary_pattern == ContentSettingsPattern::Wildcard() &&
389 info.secondary_pattern == ContentSettingsPattern::Wildcard();
392 if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS &&
393 setting == CONTENT_SETTING_ALLOW &&
394 setting_is_wildcard) {
395 // In the corner case of unrecognized plugins (which are now blocked by
396 // default) we indicate the blocked state in the UI and allow the user to
397 // whitelist.
398 radio_group.default_item = 1;
399 } else if (setting == CONTENT_SETTING_ALLOW) {
400 radio_group.default_item = kAllowButtonIndex;
401 // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|.
402 } else {
403 radio_group.default_item = 1;
404 block_setting_ = setting;
407 set_setting_is_managed(setting_source != SETTING_SOURCE_USER &&
408 setting != CONTENT_SETTING_ASK);
409 if (setting_source != SETTING_SOURCE_USER) {
410 set_radio_group_enabled(false);
411 } else {
412 set_radio_group_enabled(true);
414 selected_item_ = radio_group.default_item;
415 set_radio_group(radio_group);
418 void ContentSettingSingleRadioGroup::AddException(ContentSetting setting) {
419 if (profile()) {
420 HostContentSettingsMapFactory::GetForProfile(profile())->AddExceptionForURL(
421 bubble_content().radio_group.url,
422 bubble_content().radio_group.url,
423 content_type(),
424 setting);
428 void ContentSettingSingleRadioGroup::OnRadioClicked(int radio_index) {
429 selected_item_ = radio_index;
432 class ContentSettingCookiesBubbleModel : public ContentSettingSingleRadioGroup {
433 public:
434 ContentSettingCookiesBubbleModel(Delegate* delegate,
435 WebContents* web_contents,
436 Profile* profile);
438 ~ContentSettingCookiesBubbleModel() override;
440 private:
441 void OnCustomLinkClicked() override;
444 ContentSettingCookiesBubbleModel::ContentSettingCookiesBubbleModel(
445 Delegate* delegate,
446 WebContents* web_contents,
447 Profile* profile)
448 : ContentSettingSingleRadioGroup(delegate,
449 web_contents,
450 profile,
451 CONTENT_SETTINGS_TYPE_COOKIES) {
452 set_custom_link_enabled(true);
455 ContentSettingCookiesBubbleModel::~ContentSettingCookiesBubbleModel() {
456 // On some plattforms e.g. MacOS X it is possible to close a tab while the
457 // cookies settings bubble is open. This resets the web contents to NULL.
458 if (settings_changed() && web_contents()) {
459 CollectedCookiesInfoBarDelegate::Create(
460 InfoBarService::FromWebContents(web_contents()));
464 void ContentSettingCookiesBubbleModel::OnCustomLinkClicked() {
465 if (!web_contents())
466 return;
467 content::NotificationService::current()->Notify(
468 chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN,
469 content::Source<TabSpecificContentSettings>(
470 TabSpecificContentSettings::FromWebContents(web_contents())),
471 content::NotificationService::NoDetails());
472 delegate()->ShowCollectedCookiesDialog(web_contents());
475 class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup {
476 public:
477 ContentSettingPluginBubbleModel(Delegate* delegate,
478 WebContents* web_contents,
479 Profile* profile);
481 ~ContentSettingPluginBubbleModel() override;
483 private:
484 void OnCustomLinkClicked() override;
487 ContentSettingPluginBubbleModel::ContentSettingPluginBubbleModel(
488 Delegate* delegate,
489 WebContents* web_contents,
490 Profile* profile)
491 : ContentSettingSingleRadioGroup(delegate,
492 web_contents,
493 profile,
494 CONTENT_SETTINGS_TYPE_PLUGINS) {
495 // Disable the "Run all plugins this time" link if the setting is managed and
496 // can't be controlled by the user or if the user already clicked on the link
497 // and ran all plugins.
498 set_custom_link_enabled(!setting_is_managed() &&
499 web_contents &&
500 TabSpecificContentSettings::FromWebContents(
501 web_contents)->load_plugins_link_enabled());
502 // Build blocked plugin list.
503 if (web_contents) {
504 TabSpecificContentSettings* content_settings =
505 TabSpecificContentSettings::FromWebContents(web_contents);
507 const std::vector<base::string16>& blocked_plugins =
508 content_settings->blocked_plugin_names();
509 for (const base::string16& blocked_plugin : blocked_plugins) {
510 ListItem plugin_item(
511 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
512 IDR_BLOCKED_PLUGINS),
513 base::UTF16ToUTF8(blocked_plugin), false, 0);
514 add_list_item(plugin_item);
519 ContentSettingPluginBubbleModel::~ContentSettingPluginBubbleModel() {
520 if (settings_changed()) {
521 // If the user elected to allow all plugins then run plugins at this time.
522 if (selected_item() == kAllowButtonIndex)
523 OnCustomLinkClicked();
527 void ContentSettingPluginBubbleModel::OnCustomLinkClicked() {
528 content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble"));
529 // Web contents can be NULL if the tab was closed while the plugins
530 // settings bubble is visible.
531 if (!web_contents())
532 return;
533 #if defined(ENABLE_PLUGINS)
534 // TODO(bauerb): We should send the identifiers of blocked plugins here.
535 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
536 web_contents(), true, std::string());
537 #endif
538 set_custom_link_enabled(false);
539 TabSpecificContentSettings::FromWebContents(web_contents())->
540 set_load_plugins_link_enabled(false);
543 class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup {
544 public:
545 ContentSettingPopupBubbleModel(Delegate* delegate,
546 WebContents* web_contents,
547 Profile* profile);
548 ~ContentSettingPopupBubbleModel() override {}
550 private:
551 void OnListItemClicked(int index) override;
553 int32 item_id_from_item_index(int index) const {
554 return bubble_content().list_items[index].item_id;
558 ContentSettingPopupBubbleModel::ContentSettingPopupBubbleModel(
559 Delegate* delegate,
560 WebContents* web_contents,
561 Profile* profile)
562 : ContentSettingSingleRadioGroup(delegate,
563 web_contents,
564 profile,
565 CONTENT_SETTINGS_TYPE_POPUPS) {
566 if (web_contents) {
567 // Build blocked popup list.
568 std::map<int32, GURL> blocked_popups =
569 PopupBlockerTabHelper::FromWebContents(web_contents)
570 ->GetBlockedPopupRequests();
571 for (const std::pair<int32, GURL>& blocked_popup : blocked_popups) {
572 std::string title(blocked_popup.second.spec());
573 // The pop-up may not have a valid URL.
574 if (title.empty())
575 title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
576 ListItem popup_item(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
577 IDR_DEFAULT_FAVICON),
578 title, true, blocked_popup.first);
579 add_list_item(popup_item);
584 void ContentSettingPopupBubbleModel::OnListItemClicked(int index) {
585 if (web_contents()) {
586 PopupBlockerTabHelper::FromWebContents(web_contents())
587 ->ShowBlockedPopup(item_id_from_item_index(index));
591 // The model of the content settings bubble for media settings.
592 class ContentSettingMediaStreamBubbleModel
593 : public ContentSettingTitleAndLinkModel {
594 public:
595 ContentSettingMediaStreamBubbleModel(Delegate* delegate,
596 WebContents* web_contents,
597 Profile* profile);
599 ~ContentSettingMediaStreamBubbleModel() override;
601 void OnManageLinkClicked() override;
603 private:
604 // Helper functions to check if this bubble was invoked for microphone,
605 // camera, or both devices.
606 bool MicrophoneAccessed() const;
607 bool CameraAccessed() const;
609 void SetTitle();
610 // Sets the data for the radio buttons of the bubble.
611 void SetRadioGroup();
612 // Sets the data for the media menus of the bubble.
613 void SetMediaMenus();
614 // Set the settings management link.
615 void SetManageLink();
616 void SetCustomLink();
617 // Updates the camera and microphone setting with the passed |setting|.
618 void UpdateSettings(ContentSetting setting);
619 // Updates the camera and microphone default device with the passed |type|
620 // and device.
621 void UpdateDefaultDeviceForType(content::MediaStreamType type,
622 const std::string& device);
624 // ContentSettingBubbleModel implementation.
625 void OnRadioClicked(int radio_index) override;
626 void OnMediaMenuClicked(content::MediaStreamType type,
627 const std::string& selected_device) override;
629 // The index of the selected radio item.
630 int selected_item_;
631 // The content settings that are associated with the individual radio
632 // buttons.
633 ContentSetting radio_item_setting_[2];
634 // The state of the microphone and camera access.
635 TabSpecificContentSettings::MicrophoneCameraState state_;
638 ContentSettingMediaStreamBubbleModel::ContentSettingMediaStreamBubbleModel(
639 Delegate* delegate,
640 WebContents* web_contents,
641 Profile* profile)
642 : ContentSettingTitleAndLinkModel(
643 delegate, web_contents, profile, CONTENT_SETTINGS_TYPE_MEDIASTREAM),
644 selected_item_(0),
645 state_(TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED) {
646 // TODO(msramek): Every bubble is tied to a particular content setting.
647 // The media bubble has three states - mic only, camera only, and both.
648 // However, it is always tied to the deprecated MEDIASTREAM setting. Refactor
649 // this so that it refers to the MIC setting for microphone and CAMERA
650 // setting for camera to reduce the duplication of code in practically every
651 // method. Furthermore, it should be possible not to tie the bubble to any
652 // particular content setting type, as we still need the bubble for both
653 // camera and microphone, but should not use the deprecated MEDIASTREAM
654 // setting.
656 DCHECK(profile);
657 // Initialize the content settings associated with the individual radio
658 // buttons.
659 radio_item_setting_[0] = CONTENT_SETTING_ASK;
660 radio_item_setting_[1] = CONTENT_SETTING_BLOCK;
662 TabSpecificContentSettings* content_settings =
663 TabSpecificContentSettings::FromWebContents(web_contents);
664 state_ = content_settings->GetMicrophoneCameraState();
665 DCHECK(CameraAccessed() || MicrophoneAccessed());
667 SetTitle();
668 SetRadioGroup();
669 SetMediaMenus();
670 SetManageLink();
671 SetCustomLink();
674 ContentSettingMediaStreamBubbleModel::~ContentSettingMediaStreamBubbleModel() {
675 // On some platforms (e.g. MacOS X) it is possible to close a tab while the
676 // media stream bubble is open. This resets the web contents to NULL.
677 if (!web_contents())
678 return;
680 for (const std::pair<content::MediaStreamType, MediaMenu>& media_menu :
681 bubble_content().media_menus) {
682 if (media_menu.second.selected_device.id !=
683 media_menu.second.default_device.id) {
684 UpdateDefaultDeviceForType(media_menu.first,
685 media_menu.second.selected_device.id);
689 // Update the media settings if the radio button selection was changed.
690 if (selected_item_ != bubble_content().radio_group.default_item) {
691 UpdateSettings(radio_item_setting_[selected_item_]);
695 bool ContentSettingMediaStreamBubbleModel::MicrophoneAccessed() const {
696 return (state_ & TabSpecificContentSettings::MICROPHONE_ACCESSED) != 0;
699 bool ContentSettingMediaStreamBubbleModel::CameraAccessed() const {
700 return (state_ & TabSpecificContentSettings::CAMERA_ACCESSED) != 0;
703 void ContentSettingMediaStreamBubbleModel::OnManageLinkClicked() {
704 if (!delegate())
705 return;
707 if (MicrophoneAccessed()) {
708 delegate()->ShowContentSettingsPage(CameraAccessed()
709 ? CONTENT_SETTINGS_TYPE_MEDIASTREAM
710 : CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
711 } else {
712 delegate()->ShowContentSettingsPage(
713 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
717 void ContentSettingMediaStreamBubbleModel::SetTitle() {
718 DCHECK(CameraAccessed() || MicrophoneAccessed());
719 int title_id = 0;
720 if (state_ & TabSpecificContentSettings::MICROPHONE_BLOCKED) {
721 title_id = (state_ & TabSpecificContentSettings::CAMERA_BLOCKED) ?
722 IDS_MICROPHONE_CAMERA_BLOCKED : IDS_MICROPHONE_BLOCKED;
723 } else if (state_ & TabSpecificContentSettings::CAMERA_BLOCKED) {
724 title_id = IDS_CAMERA_BLOCKED;
725 } else if (MicrophoneAccessed()) {
726 title_id = CameraAccessed() ? IDS_MICROPHONE_CAMERA_ALLOWED
727 : IDS_MICROPHONE_ACCESSED;
728 } else if (CameraAccessed()) {
729 title_id = IDS_CAMERA_ACCESSED;
731 set_title(l10n_util::GetStringUTF8(title_id));
734 void ContentSettingMediaStreamBubbleModel::SetRadioGroup() {
735 TabSpecificContentSettings* content_settings =
736 TabSpecificContentSettings::FromWebContents(web_contents());
737 GURL url = content_settings->media_stream_access_origin();
738 RadioGroup radio_group;
739 radio_group.url = url;
741 base::string16 display_host_utf16 =
742 url_formatter::FormatUrlForSecurityDisplay(
743 url, profile()->GetPrefs()->GetString(prefs::kAcceptLanguages));
744 std::string display_host(base::UTF16ToUTF8(display_host_utf16));
745 if (display_host.empty())
746 display_host = url.spec();
748 DCHECK(CameraAccessed() || MicrophoneAccessed());
749 int radio_allow_label_id = 0;
750 int radio_block_label_id = 0;
751 if (state_ & (TabSpecificContentSettings::MICROPHONE_BLOCKED |
752 TabSpecificContentSettings::CAMERA_BLOCKED)) {
753 if (content::IsOriginSecure(url)) {
754 radio_item_setting_[0] = CONTENT_SETTING_ALLOW;
755 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ALLOW;
756 if (MicrophoneAccessed())
757 radio_allow_label_id = CameraAccessed() ?
758 IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ALLOW :
759 IDS_BLOCKED_MEDIASTREAM_MIC_ALLOW;
760 } else {
761 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ASK;
762 if (MicrophoneAccessed())
763 radio_allow_label_id = CameraAccessed() ?
764 IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ASK :
765 IDS_BLOCKED_MEDIASTREAM_MIC_ASK;
767 radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_NO_ACTION;
768 if (MicrophoneAccessed())
769 radio_block_label_id = CameraAccessed() ?
770 IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION :
771 IDS_BLOCKED_MEDIASTREAM_MIC_NO_ACTION;
772 } else {
773 if (MicrophoneAccessed() && CameraAccessed()) {
774 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION;
775 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_BLOCK;
776 } else if (MicrophoneAccessed()) {
777 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_NO_ACTION;
778 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_BLOCK;
779 } else {
780 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_NO_ACTION;
781 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_BLOCK;
784 selected_item_ =
785 (MicrophoneAccessed() && content_settings->IsContentBlocked(
786 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)) ||
787 (CameraAccessed() && content_settings->IsContentBlocked(
788 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)) ? 1 : 0;
790 std::string radio_allow_label = l10n_util::GetStringFUTF8(
791 radio_allow_label_id, base::UTF8ToUTF16(display_host));
792 std::string radio_block_label =
793 l10n_util::GetStringUTF8(radio_block_label_id);
795 radio_group.default_item = selected_item_;
796 radio_group.radio_items.push_back(radio_allow_label);
797 radio_group.radio_items.push_back(radio_block_label);
799 set_radio_group(radio_group);
800 set_radio_group_enabled(true);
803 void ContentSettingMediaStreamBubbleModel::UpdateSettings(
804 ContentSetting setting) {
805 if (profile()) {
806 HostContentSettingsMap* content_settings =
807 HostContentSettingsMapFactory::GetForProfile(profile());
808 TabSpecificContentSettings* tab_content_settings =
809 TabSpecificContentSettings::FromWebContents(web_contents());
810 // The same patterns must be used as in other places (e.g. the infobar) in
811 // order to override the existing rule. Otherwise a new rule is created.
812 // TODO(markusheintz): Extract to a helper so that there is only a single
813 // place to touch.
814 ContentSettingsPattern primary_pattern =
815 ContentSettingsPattern::FromURLNoWildcard(
816 tab_content_settings->media_stream_access_origin());
817 ContentSettingsPattern secondary_pattern =
818 ContentSettingsPattern::Wildcard();
819 if (MicrophoneAccessed()) {
820 content_settings->SetContentSetting(
821 primary_pattern, secondary_pattern,
822 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting);
824 if (CameraAccessed()) {
825 content_settings->SetContentSetting(
826 primary_pattern, secondary_pattern,
827 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting);
832 void ContentSettingMediaStreamBubbleModel::UpdateDefaultDeviceForType(
833 content::MediaStreamType type,
834 const std::string& device) {
835 PrefService* prefs = profile()->GetPrefs();
836 if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
837 prefs->SetString(prefs::kDefaultAudioCaptureDevice, device);
838 } else {
839 DCHECK_EQ(content::MEDIA_DEVICE_VIDEO_CAPTURE, type);
840 prefs->SetString(prefs::kDefaultVideoCaptureDevice, device);
844 void ContentSettingMediaStreamBubbleModel::SetMediaMenus() {
845 TabSpecificContentSettings* content_settings =
846 TabSpecificContentSettings::FromWebContents(web_contents());
847 const std::string& requested_microphone =
848 content_settings->media_stream_requested_audio_device();
849 const std::string& requested_camera =
850 content_settings->media_stream_requested_video_device();
852 // Add microphone menu.
853 PrefService* prefs = profile()->GetPrefs();
854 MediaCaptureDevicesDispatcher* dispatcher =
855 MediaCaptureDevicesDispatcher::GetInstance();
856 const content::MediaStreamDevices& microphones =
857 dispatcher->GetAudioCaptureDevices();
859 if (MicrophoneAccessed()) {
860 MediaMenu mic_menu;
861 mic_menu.label = l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_MIC_LABEL);
862 if (!microphones.empty()) {
863 std::string preferred_mic;
864 if (requested_microphone.empty()) {
865 preferred_mic = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
866 mic_menu.disabled = false;
867 } else {
868 // Set the |disabled| to true in order to disable the device selection
869 // menu on the media settings bubble. This must be done if the website
870 // manages the microphone devices itself.
871 preferred_mic = requested_microphone;
872 mic_menu.disabled = true;
875 mic_menu.default_device = GetMediaDeviceById(preferred_mic, microphones);
876 mic_menu.selected_device = mic_menu.default_device;
878 add_media_menu(content::MEDIA_DEVICE_AUDIO_CAPTURE, mic_menu);
881 if (CameraAccessed()) {
882 const content::MediaStreamDevices& cameras =
883 dispatcher->GetVideoCaptureDevices();
884 MediaMenu camera_menu;
885 camera_menu.label =
886 l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_CAMERA_LABEL);
887 if (!cameras.empty()) {
888 std::string preferred_camera;
889 if (requested_camera.empty()) {
890 preferred_camera = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
891 camera_menu.disabled = false;
892 } else {
893 // Disable the menu since the website is managing the camera devices
894 // itself.
895 preferred_camera = requested_camera;
896 camera_menu.disabled = true;
899 camera_menu.default_device =
900 GetMediaDeviceById(preferred_camera, cameras);
901 camera_menu.selected_device = camera_menu.default_device;
903 add_media_menu(content::MEDIA_DEVICE_VIDEO_CAPTURE, camera_menu);
907 void ContentSettingMediaStreamBubbleModel::SetManageLink() {
908 // By default, the manage link refers to both media types. We only need
909 // to change the link text if only one media type was accessed.
910 if (CameraAccessed() && MicrophoneAccessed())
911 return;
913 set_manage_link(l10n_util::GetStringUTF8(MicrophoneAccessed()
914 ? IDS_MEDIASTREAM_MICROPHONE_BUBBLE_MANAGE_LINK
915 : IDS_MEDIASTREAM_CAMERA_BUBBLE_MANAGE_LINK));
918 void ContentSettingMediaStreamBubbleModel::SetCustomLink() {
919 TabSpecificContentSettings* content_settings =
920 TabSpecificContentSettings::FromWebContents(web_contents());
921 if (content_settings->IsMicrophoneCameraStateChanged()) {
922 set_custom_link(l10n_util::GetStringUTF8(
923 IDS_MEDIASTREAM_SETTING_CHANGED_MESSAGE));
927 void ContentSettingMediaStreamBubbleModel::OnRadioClicked(int radio_index) {
928 selected_item_ = radio_index;
931 void ContentSettingMediaStreamBubbleModel::OnMediaMenuClicked(
932 content::MediaStreamType type,
933 const std::string& selected_device_id) {
934 DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
935 type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
936 DCHECK_EQ(1U, bubble_content().media_menus.count(type));
937 MediaCaptureDevicesDispatcher* dispatcher =
938 MediaCaptureDevicesDispatcher::GetInstance();
939 const content::MediaStreamDevices& devices =
940 (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) ?
941 dispatcher->GetAudioCaptureDevices() :
942 dispatcher->GetVideoCaptureDevices();
943 set_selected_device(GetMediaDeviceById(selected_device_id, devices));
946 class ContentSettingDomainListBubbleModel
947 : public ContentSettingTitleAndLinkModel {
948 public:
949 ContentSettingDomainListBubbleModel(Delegate* delegate,
950 WebContents* web_contents,
951 Profile* profile,
952 ContentSettingsType content_type);
953 ~ContentSettingDomainListBubbleModel() override {}
955 private:
956 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
957 void SetDomainsAndCustomLink();
958 void OnCustomLinkClicked() override;
961 ContentSettingDomainListBubbleModel::ContentSettingDomainListBubbleModel(
962 Delegate* delegate,
963 WebContents* web_contents,
964 Profile* profile,
965 ContentSettingsType content_type)
966 : ContentSettingTitleAndLinkModel(
967 delegate, web_contents, profile, content_type) {
968 DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type) <<
969 "SetDomains currently only supports geolocation content type";
970 SetDomainsAndCustomLink();
973 void ContentSettingDomainListBubbleModel::MaybeAddDomainList(
974 const std::set<std::string>& hosts, int title_id) {
975 if (!hosts.empty()) {
976 DomainList domain_list;
977 domain_list.title = l10n_util::GetStringUTF8(title_id);
978 domain_list.hosts = hosts;
979 add_domain_list(domain_list);
983 void ContentSettingDomainListBubbleModel::SetDomainsAndCustomLink() {
984 TabSpecificContentSettings* content_settings =
985 TabSpecificContentSettings::FromWebContents(web_contents());
986 const ContentSettingsUsagesState& usages =
987 content_settings->geolocation_usages_state();
988 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state;
989 unsigned int tab_state_flags = 0;
990 usages.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
991 // Divide the tab's current geolocation users into sets according to their
992 // permission state.
993 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW],
994 IDS_GEOLOCATION_BUBBLE_SECTION_ALLOWED);
996 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK],
997 IDS_GEOLOCATION_BUBBLE_SECTION_DENIED);
999 if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) {
1000 set_custom_link(l10n_util::GetStringUTF8(
1001 IDS_GEOLOCATION_BUBBLE_CLEAR_LINK));
1002 set_custom_link_enabled(true);
1003 } else if (tab_state_flags &
1004 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) {
1005 set_custom_link(l10n_util::GetStringUTF8(
1006 IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
1010 void ContentSettingDomainListBubbleModel::OnCustomLinkClicked() {
1011 if (!web_contents())
1012 return;
1013 // Reset this embedder's entry to default for each of the requesting
1014 // origins currently on the page.
1015 const GURL& embedder_url = web_contents()->GetURL();
1016 TabSpecificContentSettings* content_settings =
1017 TabSpecificContentSettings::FromWebContents(web_contents());
1018 const ContentSettingsUsagesState::StateMap& state_map =
1019 content_settings->geolocation_usages_state().state_map();
1020 HostContentSettingsMap* settings_map =
1021 HostContentSettingsMapFactory::GetForProfile(profile());
1023 for (const std::pair<GURL, ContentSetting>& map_entry : state_map) {
1024 settings_map->SetContentSetting(
1025 ContentSettingsPattern::FromURLNoWildcard(map_entry.first),
1026 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
1027 CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
1028 CONTENT_SETTING_DEFAULT);
1032 class ContentSettingMixedScriptBubbleModel
1033 : public ContentSettingTitleLinkAndCustomModel {
1034 public:
1035 ContentSettingMixedScriptBubbleModel(Delegate* delegate,
1036 WebContents* web_contents,
1037 Profile* profile);
1039 ~ContentSettingMixedScriptBubbleModel() override {}
1041 private:
1042 void OnCustomLinkClicked() override;
1045 ContentSettingMixedScriptBubbleModel::ContentSettingMixedScriptBubbleModel(
1046 Delegate* delegate,
1047 WebContents* web_contents,
1048 Profile* profile)
1049 : ContentSettingTitleLinkAndCustomModel(delegate,
1050 web_contents,
1051 profile,
1052 CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) {
1053 content_settings::RecordMixedScriptAction(
1054 content_settings::MIXED_SCRIPT_ACTION_DISPLAYED_BUBBLE);
1055 set_custom_link_enabled(true);
1058 void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() {
1059 DCHECK(web_contents());
1060 web_contents()->SendToAllFrames(
1061 new ChromeViewMsg_SetAllowRunningInsecureContent(MSG_ROUTING_NONE, true));
1062 web_contents()->GetMainFrame()->Send(new ChromeViewMsg_ReloadFrame(
1063 web_contents()->GetMainFrame()->GetRoutingID()));
1065 content_settings::RecordMixedScriptAction(
1066 content_settings::MIXED_SCRIPT_ACTION_CLICKED_ALLOW);
1067 content_settings::RecordMixedScriptActionWithRAPPOR(
1068 content_settings::MIXED_SCRIPT_ACTION_CLICKED_ALLOW,
1069 web_contents()->GetLastCommittedURL());
1072 ContentSettingRPHBubbleModel::ContentSettingRPHBubbleModel(
1073 Delegate* delegate,
1074 WebContents* web_contents,
1075 Profile* profile,
1076 ProtocolHandlerRegistry* registry)
1077 : ContentSettingTitleAndLinkModel(delegate,
1078 web_contents,
1079 profile,
1080 CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS),
1081 selected_item_(0),
1082 registry_(registry),
1083 pending_handler_(ProtocolHandler::EmptyProtocolHandler()),
1084 previous_handler_(ProtocolHandler::EmptyProtocolHandler()) {
1085 TabSpecificContentSettings* content_settings =
1086 TabSpecificContentSettings::FromWebContents(web_contents);
1087 pending_handler_ = content_settings->pending_protocol_handler();
1088 previous_handler_ = content_settings->previous_protocol_handler();
1090 base::string16 protocol;
1091 if (pending_handler_.protocol() == "mailto") {
1092 protocol = l10n_util::GetStringUTF16(
1093 IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME);
1094 } else if (pending_handler_.protocol() == "webcal") {
1095 protocol = l10n_util::GetStringUTF16(
1096 IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME);
1097 } else {
1098 protocol = base::UTF8ToUTF16(pending_handler_.protocol());
1101 // Note that we ignore the |title| parameter.
1102 if (previous_handler_.IsEmpty()) {
1103 set_title(l10n_util::GetStringFUTF8(
1104 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM,
1105 base::UTF8ToUTF16(pending_handler_.url().host()),
1106 protocol));
1107 } else {
1108 set_title(l10n_util::GetStringFUTF8(
1109 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE,
1110 base::UTF8ToUTF16(pending_handler_.url().host()),
1111 protocol,
1112 base::UTF8ToUTF16(previous_handler_.url().host())));
1115 std::string radio_allow_label =
1116 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_ACCEPT);
1117 std::string radio_deny_label =
1118 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_DENY);
1119 std::string radio_ignore_label =
1120 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_IGNORE);
1122 GURL url = web_contents->GetURL();
1123 RadioGroup radio_group;
1124 radio_group.url = url;
1126 radio_group.radio_items.push_back(radio_allow_label);
1127 radio_group.radio_items.push_back(radio_deny_label);
1128 radio_group.radio_items.push_back(radio_ignore_label);
1129 ContentSetting setting =
1130 content_settings->pending_protocol_handler_setting();
1131 if (setting == CONTENT_SETTING_ALLOW)
1132 radio_group.default_item = RPH_ALLOW;
1133 else if (setting == CONTENT_SETTING_BLOCK)
1134 radio_group.default_item = RPH_BLOCK;
1135 else
1136 radio_group.default_item = RPH_IGNORE;
1138 selected_item_ = radio_group.default_item;
1139 set_radio_group_enabled(true);
1140 set_radio_group(radio_group);
1143 void ContentSettingRPHBubbleModel::OnRadioClicked(int radio_index) {
1144 if (selected_item_ == radio_index)
1145 return;
1147 selected_item_ = radio_index;
1149 if (radio_index == RPH_ALLOW)
1150 RegisterProtocolHandler();
1151 else if (radio_index == RPH_BLOCK)
1152 UnregisterProtocolHandler();
1153 else if (radio_index == RPH_IGNORE)
1154 IgnoreProtocolHandler();
1155 else
1156 NOTREACHED();
1159 void ContentSettingRPHBubbleModel::OnDoneClicked() {
1160 // The user has one chance to deal with the RPH content setting UI,
1161 // then we remove it.
1162 TabSpecificContentSettings::FromWebContents(web_contents())->
1163 ClearPendingProtocolHandler();
1164 content::NotificationService::current()->Notify(
1165 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
1166 content::Source<WebContents>(web_contents()),
1167 content::NotificationService::NoDetails());
1170 void ContentSettingRPHBubbleModel::RegisterProtocolHandler() {
1171 // A no-op if the handler hasn't been ignored, but needed in case the user
1172 // selects sequences like register/ignore/register.
1173 registry_->RemoveIgnoredHandler(pending_handler_);
1175 registry_->OnAcceptRegisterProtocolHandler(pending_handler_);
1176 TabSpecificContentSettings::FromWebContents(web_contents())->
1177 set_pending_protocol_handler_setting(CONTENT_SETTING_ALLOW);
1180 void ContentSettingRPHBubbleModel::UnregisterProtocolHandler() {
1181 registry_->OnDenyRegisterProtocolHandler(pending_handler_);
1182 TabSpecificContentSettings::FromWebContents(web_contents())->
1183 set_pending_protocol_handler_setting(CONTENT_SETTING_BLOCK);
1184 ClearOrSetPreviousHandler();
1187 void ContentSettingRPHBubbleModel::IgnoreProtocolHandler() {
1188 registry_->OnIgnoreRegisterProtocolHandler(pending_handler_);
1189 TabSpecificContentSettings::FromWebContents(web_contents())->
1190 set_pending_protocol_handler_setting(CONTENT_SETTING_DEFAULT);
1191 ClearOrSetPreviousHandler();
1194 void ContentSettingRPHBubbleModel::ClearOrSetPreviousHandler() {
1195 if (previous_handler_.IsEmpty()) {
1196 registry_->ClearDefault(pending_handler_.protocol());
1197 } else {
1198 registry_->OnAcceptRegisterProtocolHandler(previous_handler_);
1202 class ContentSettingMidiSysExBubbleModel
1203 : public ContentSettingTitleAndLinkModel {
1204 public:
1205 ContentSettingMidiSysExBubbleModel(Delegate* delegate,
1206 WebContents* web_contents,
1207 Profile* profile);
1208 ~ContentSettingMidiSysExBubbleModel() override {}
1210 private:
1211 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
1212 void SetDomainsAndCustomLink();
1213 void OnCustomLinkClicked() override;
1216 ContentSettingMidiSysExBubbleModel::ContentSettingMidiSysExBubbleModel(
1217 Delegate* delegate,
1218 WebContents* web_contents,
1219 Profile* profile)
1220 : ContentSettingTitleAndLinkModel(delegate,
1221 web_contents,
1222 profile,
1223 CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
1224 SetDomainsAndCustomLink();
1227 void ContentSettingMidiSysExBubbleModel::MaybeAddDomainList(
1228 const std::set<std::string>& hosts, int title_id) {
1229 if (!hosts.empty()) {
1230 DomainList domain_list;
1231 domain_list.title = l10n_util::GetStringUTF8(title_id);
1232 domain_list.hosts = hosts;
1233 add_domain_list(domain_list);
1237 void ContentSettingMidiSysExBubbleModel::SetDomainsAndCustomLink() {
1238 TabSpecificContentSettings* content_settings =
1239 TabSpecificContentSettings::FromWebContents(web_contents());
1240 const ContentSettingsUsagesState& usages_state =
1241 content_settings->midi_usages_state();
1242 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state;
1243 unsigned int tab_state_flags = 0;
1244 usages_state.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
1245 // Divide the tab's current MIDI sysex users into sets according to their
1246 // permission state.
1247 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW],
1248 IDS_MIDI_SYSEX_BUBBLE_ALLOWED);
1250 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK],
1251 IDS_MIDI_SYSEX_BUBBLE_DENIED);
1253 if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) {
1254 set_custom_link(l10n_util::GetStringUTF8(
1255 IDS_MIDI_SYSEX_BUBBLE_CLEAR_LINK));
1256 set_custom_link_enabled(true);
1257 } else if (tab_state_flags &
1258 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) {
1259 set_custom_link(l10n_util::GetStringUTF8(
1260 IDS_MIDI_SYSEX_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
1264 void ContentSettingMidiSysExBubbleModel::OnCustomLinkClicked() {
1265 if (!web_contents())
1266 return;
1267 // Reset this embedder's entry to default for each of the requesting
1268 // origins currently on the page.
1269 const GURL& embedder_url = web_contents()->GetURL();
1270 TabSpecificContentSettings* content_settings =
1271 TabSpecificContentSettings::FromWebContents(web_contents());
1272 const ContentSettingsUsagesState::StateMap& state_map =
1273 content_settings->midi_usages_state().state_map();
1274 HostContentSettingsMap* settings_map =
1275 HostContentSettingsMapFactory::GetForProfile(profile());
1277 for (const std::pair<GURL, ContentSetting>& map_entry : state_map) {
1278 settings_map->SetContentSetting(
1279 ContentSettingsPattern::FromURLNoWildcard(map_entry.first),
1280 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
1281 CONTENT_SETTINGS_TYPE_MIDI_SYSEX, std::string(),
1282 CONTENT_SETTING_DEFAULT);
1286 // static
1287 const std::set<ContentSettingsType>&
1288 ContentSettingBubbleModel::GetSupportedBubbleTypes() {
1289 CR_DEFINE_STATIC_LOCAL(
1290 const std::set<ContentSettingsType>, supported_bubble_types,
1291 (kSupportedBubbleTypes,
1292 kSupportedBubbleTypes + arraysize(kSupportedBubbleTypes)));
1293 return supported_bubble_types;
1296 // static
1297 ContentSettingBubbleModel*
1298 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
1299 Delegate* delegate,
1300 WebContents* web_contents,
1301 Profile* profile,
1302 ContentSettingsType content_type) {
1303 DCHECK(ContainsKey(GetSupportedBubbleTypes(), content_type));
1304 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
1305 return new ContentSettingCookiesBubbleModel(delegate, web_contents,
1306 profile);
1308 if (content_type == CONTENT_SETTINGS_TYPE_POPUPS) {
1309 return new ContentSettingPopupBubbleModel(delegate, web_contents, profile);
1311 if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
1312 return new ContentSettingDomainListBubbleModel(delegate, web_contents,
1313 profile, content_type);
1315 if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
1316 return new ContentSettingMediaStreamBubbleModel(delegate, web_contents,
1317 profile);
1319 if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
1320 return new ContentSettingPluginBubbleModel(delegate, web_contents, profile);
1322 if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) {
1323 return new ContentSettingMixedScriptBubbleModel(delegate, web_contents,
1324 profile);
1326 if (content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
1327 ProtocolHandlerRegistry* registry =
1328 ProtocolHandlerRegistryFactory::GetForBrowserContext(profile);
1329 return new ContentSettingRPHBubbleModel(delegate, web_contents, profile,
1330 registry);
1332 if (content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
1333 return new ContentSettingMidiSysExBubbleModel(delegate, web_contents,
1334 profile);
1336 return new ContentSettingSingleRadioGroup(delegate, web_contents, profile,
1337 content_type);
1340 ContentSettingBubbleModel::ContentSettingBubbleModel(
1341 WebContents* web_contents,
1342 Profile* profile,
1343 ContentSettingsType content_type)
1344 : web_contents_(web_contents),
1345 profile_(profile),
1346 content_type_(content_type),
1347 setting_is_managed_(false) {
1348 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
1349 content::Source<WebContents>(web_contents));
1350 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
1351 content::Source<Profile>(profile_));
1354 ContentSettingBubbleModel::~ContentSettingBubbleModel() {
1357 ContentSettingBubbleModel::RadioGroup::RadioGroup() : default_item(0) {}
1359 ContentSettingBubbleModel::RadioGroup::~RadioGroup() {}
1361 ContentSettingBubbleModel::DomainList::DomainList() {}
1363 ContentSettingBubbleModel::DomainList::~DomainList() {}
1365 ContentSettingBubbleModel::MediaMenu::MediaMenu() : disabled(false) {}
1367 ContentSettingBubbleModel::MediaMenu::~MediaMenu() {}
1369 ContentSettingBubbleModel::BubbleContent::BubbleContent()
1370 : radio_group_enabled(false),
1371 custom_link_enabled(false) {
1374 ContentSettingBubbleModel::BubbleContent::~BubbleContent() {}
1376 void ContentSettingBubbleModel::Observe(
1377 int type,
1378 const content::NotificationSource& source,
1379 const content::NotificationDetails& details) {
1380 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
1381 DCHECK_EQ(web_contents_,
1382 content::Source<WebContents>(source).ptr());
1383 web_contents_ = NULL;
1384 } else {
1385 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
1386 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
1387 profile_ = NULL;