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/tab_specific_content_settings.h"
16 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
17 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
18 #include "chrome/browser/infobars/infobar_service.h"
19 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
20 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
23 #include "chrome/browser/ui/browser_navigator.h"
24 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
25 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/pref_names.h"
28 #include "chrome/common/render_messages.h"
29 #include "chrome/grit/generated_resources.h"
30 #include "components/content_settings/content/common/content_settings_messages.h"
31 #include "components/content_settings/core/browser/content_settings_utils.h"
32 #include "components/content_settings/core/browser/cookie_settings.h"
33 #include "components/content_settings/core/common/content_settings.h"
34 #include "components/url_formatter/elide_url.h"
35 #include "content/public/browser/notification_service.h"
36 #include "content/public/browser/render_frame_host.h"
37 #include "content/public/browser/render_process_host.h"
38 #include "content/public/browser/render_view_host.h"
39 #include "content/public/browser/user_metrics.h"
40 #include "content/public/browser/web_contents.h"
41 #include "content/public/browser/web_contents_delegate.h"
42 #include "content/public/common/origin_util.h"
43 #include "grit/components_strings.h"
44 #include "grit/theme_resources.h"
45 #include "ui/base/l10n/l10n_util.h"
46 #include "ui/base/resource/resource_bundle.h"
47 #include "ui/resources/grit/ui_resources.h"
49 using base::UserMetricsAction
;
50 using content::WebContents
;
51 using content_settings::SettingInfo
;
52 using content_settings::SettingSource
;
53 using content_settings::SETTING_SOURCE_USER
;
54 using content_settings::SETTING_SOURCE_NONE
;
58 const int kAllowButtonIndex
= 0;
61 const ContentSettingsType kSupportedBubbleTypes
[] = {
62 CONTENT_SETTINGS_TYPE_COOKIES
,
63 CONTENT_SETTINGS_TYPE_IMAGES
,
64 CONTENT_SETTINGS_TYPE_JAVASCRIPT
,
65 CONTENT_SETTINGS_TYPE_PPAPI_BROKER
,
66 CONTENT_SETTINGS_TYPE_PLUGINS
,
67 CONTENT_SETTINGS_TYPE_POPUPS
,
68 CONTENT_SETTINGS_TYPE_GEOLOCATION
,
69 CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
,
70 CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS
,
71 CONTENT_SETTINGS_TYPE_MEDIASTREAM
,
72 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
,
73 CONTENT_SETTINGS_TYPE_MIDI_SYSEX
,
76 // These states must match the order of appearance of the radio buttons
77 // in the XIB file for the Mac port.
84 struct ContentSettingsTypeIdEntry
{
85 ContentSettingsType type
;
89 int GetIdForContentType(const ContentSettingsTypeIdEntry
* entries
,
91 ContentSettingsType type
) {
92 for (size_t i
= 0; i
< num_entries
; ++i
) {
93 if (entries
[i
].type
== type
)
99 const content::MediaStreamDevice
& GetMediaDeviceById(
100 const std::string
& device_id
,
101 const content::MediaStreamDevices
& devices
) {
102 DCHECK(!devices
.empty());
103 for (const content::MediaStreamDevice
& device
: devices
) {
104 if (device
.id
== device_id
)
108 // A device with the |device_id| was not found. It is likely that the device
109 // has been unplugged from the OS. Return the first device as the default
111 return *devices
.begin();
116 ContentSettingTitleAndLinkModel::ContentSettingTitleAndLinkModel(
118 WebContents
* web_contents
,
120 ContentSettingsType content_type
)
121 : ContentSettingBubbleModel(web_contents
, profile
, content_type
),
122 delegate_(delegate
) {
123 // Notifications do not have a bubble.
124 DCHECK_NE(content_type
, CONTENT_SETTINGS_TYPE_NOTIFICATIONS
);
130 void ContentSettingTitleAndLinkModel::SetTitle() {
131 TabSpecificContentSettings
* content_settings
= NULL
;
132 if (web_contents()) {
134 TabSpecificContentSettings::FromWebContents(web_contents());
137 static const ContentSettingsTypeIdEntry kBlockedTitleIDs
[] = {
138 {CONTENT_SETTINGS_TYPE_COOKIES
, IDS_BLOCKED_COOKIES_TITLE
},
139 {CONTENT_SETTINGS_TYPE_IMAGES
, IDS_BLOCKED_IMAGES_TITLE
},
140 {CONTENT_SETTINGS_TYPE_JAVASCRIPT
, IDS_BLOCKED_JAVASCRIPT_TITLE
},
141 {CONTENT_SETTINGS_TYPE_PLUGINS
, IDS_BLOCKED_PLUGINS_TITLE
},
142 {CONTENT_SETTINGS_TYPE_POPUPS
, IDS_BLOCKED_POPUPS_TITLE
},
143 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
,
144 IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT
},
145 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER
,
146 IDS_BLOCKED_PPAPI_BROKER_TITLE
},
147 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
, IDS_BLOCKED_DOWNLOAD_TITLE
},
149 // Fields as for kBlockedTitleIDs, above.
150 static const ContentSettingsTypeIdEntry kAccessedTitleIDs
[] = {
151 {CONTENT_SETTINGS_TYPE_COOKIES
, IDS_ACCESSED_COOKIES_TITLE
},
152 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER
, IDS_ALLOWED_PPAPI_BROKER_TITLE
},
153 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
, IDS_ALLOWED_DOWNLOAD_TITLE
},
155 const ContentSettingsTypeIdEntry
*title_ids
= kBlockedTitleIDs
;
156 size_t num_title_ids
= arraysize(kBlockedTitleIDs
);
157 if (content_settings
&& content_settings
->IsContentAllowed(content_type()) &&
158 !content_settings
->IsContentBlocked(content_type())) {
159 title_ids
= kAccessedTitleIDs
;
160 num_title_ids
= arraysize(kAccessedTitleIDs
);
163 GetIdForContentType(title_ids
, num_title_ids
, content_type());
165 set_title(l10n_util::GetStringUTF8(title_id
));
168 void ContentSettingTitleAndLinkModel::SetManageLink() {
169 static const ContentSettingsTypeIdEntry kLinkIDs
[] = {
170 {CONTENT_SETTINGS_TYPE_COOKIES
, IDS_BLOCKED_COOKIES_LINK
},
171 {CONTENT_SETTINGS_TYPE_IMAGES
, IDS_BLOCKED_IMAGES_LINK
},
172 {CONTENT_SETTINGS_TYPE_JAVASCRIPT
, IDS_BLOCKED_JAVASCRIPT_LINK
},
173 {CONTENT_SETTINGS_TYPE_PLUGINS
, IDS_BLOCKED_PLUGINS_LINK
},
174 {CONTENT_SETTINGS_TYPE_POPUPS
, IDS_BLOCKED_POPUPS_LINK
},
175 {CONTENT_SETTINGS_TYPE_GEOLOCATION
, IDS_GEOLOCATION_BUBBLE_MANAGE_LINK
},
176 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
, IDS_LEARN_MORE
},
177 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS
, IDS_HANDLERS_BUBBLE_MANAGE_LINK
},
178 {CONTENT_SETTINGS_TYPE_MEDIASTREAM
, IDS_MEDIASTREAM_BUBBLE_MANAGE_LINK
},
179 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER
, IDS_PPAPI_BROKER_BUBBLE_MANAGE_LINK
},
180 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
, IDS_BLOCKED_DOWNLOADS_LINK
},
181 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX
, IDS_MIDI_SYSEX_BUBBLE_MANAGE_LINK
},
183 set_manage_link(l10n_util::GetStringUTF8(
184 GetIdForContentType(kLinkIDs
, arraysize(kLinkIDs
), content_type())));
187 void ContentSettingTitleAndLinkModel::OnManageLinkClicked() {
189 delegate_
->ShowContentSettingsPage(content_type());
192 void ContentSettingTitleAndLinkModel::SetLearnMoreLink() {
193 static const ContentSettingsTypeIdEntry kLearnMoreIDs
[] = {
194 {CONTENT_SETTINGS_TYPE_PLUGINS
, IDS_LEARN_MORE
},
197 GetIdForContentType(kLearnMoreIDs
, arraysize(kLearnMoreIDs
),
200 set_learn_more_link(l10n_util::GetStringUTF8(learn_more_id
));
203 void ContentSettingTitleAndLinkModel::OnLearnMoreLinkClicked() {
205 delegate_
->ShowLearnMorePage(content_type());
208 class ContentSettingTitleLinkAndCustomModel
209 : public ContentSettingTitleAndLinkModel
{
211 ContentSettingTitleLinkAndCustomModel(Delegate
* delegate
,
212 WebContents
* web_contents
,
214 ContentSettingsType content_type
);
215 ~ContentSettingTitleLinkAndCustomModel() override
{}
218 void SetCustomLink();
219 void OnCustomLinkClicked() override
{}
222 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel(
224 WebContents
* web_contents
,
226 ContentSettingsType content_type
)
227 : ContentSettingTitleAndLinkModel(
228 delegate
, web_contents
, profile
, content_type
) {
232 void ContentSettingTitleLinkAndCustomModel::SetCustomLink() {
233 static const ContentSettingsTypeIdEntry kCustomIDs
[] = {
234 {CONTENT_SETTINGS_TYPE_COOKIES
, IDS_BLOCKED_COOKIES_INFO
},
235 {CONTENT_SETTINGS_TYPE_PLUGINS
, IDS_BLOCKED_PLUGINS_LOAD_ALL
},
236 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
, IDS_ALLOW_INSECURE_CONTENT_BUTTON
},
239 GetIdForContentType(kCustomIDs
, arraysize(kCustomIDs
), content_type());
241 set_custom_link(l10n_util::GetStringUTF8(custom_link_id
));
244 class ContentSettingSingleRadioGroup
245 : public ContentSettingTitleLinkAndCustomModel
{
247 ContentSettingSingleRadioGroup(Delegate
* delegate
,
248 WebContents
* web_contents
,
250 ContentSettingsType content_type
);
251 ~ContentSettingSingleRadioGroup() override
;
254 bool settings_changed() const;
255 int selected_item() const { return selected_item_
; }
258 void SetRadioGroup();
259 void AddException(ContentSetting setting
);
260 void OnRadioClicked(int radio_index
) override
;
262 ContentSetting block_setting_
;
266 ContentSettingSingleRadioGroup::ContentSettingSingleRadioGroup(
268 WebContents
* web_contents
,
270 ContentSettingsType content_type
)
271 : ContentSettingTitleLinkAndCustomModel(delegate
, web_contents
, profile
,
273 block_setting_(CONTENT_SETTING_BLOCK
),
278 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() {
279 if (settings_changed()) {
280 ContentSetting setting
=
281 selected_item_
== kAllowButtonIndex
?
282 CONTENT_SETTING_ALLOW
:
284 AddException(setting
);
288 bool ContentSettingSingleRadioGroup::settings_changed() const {
289 return selected_item_
!= bubble_content().radio_group
.default_item
;
292 // Initialize the radio group by setting the appropriate labels for the
293 // content type and setting the default value based on the content setting.
294 void ContentSettingSingleRadioGroup::SetRadioGroup() {
295 GURL url
= web_contents()->GetURL();
296 base::string16 display_host
= url_formatter::FormatUrlForSecurityDisplay(
297 url
, profile()->GetPrefs()->GetString(prefs::kAcceptLanguages
));
298 if (display_host
.empty())
299 display_host
= base::ASCIIToUTF16(url
.spec());
301 TabSpecificContentSettings
* content_settings
=
302 TabSpecificContentSettings::FromWebContents(web_contents());
304 !content_settings
->IsContentBlocked(content_type());
306 content_settings
->IsContentAllowed(content_type()));
308 RadioGroup radio_group
;
309 radio_group
.url
= url
;
311 static const ContentSettingsTypeIdEntry kBlockedAllowIDs
[] = {
312 {CONTENT_SETTINGS_TYPE_COOKIES
, IDS_BLOCKED_COOKIES_UNBLOCK
},
313 {CONTENT_SETTINGS_TYPE_IMAGES
, IDS_BLOCKED_IMAGES_UNBLOCK
},
314 {CONTENT_SETTINGS_TYPE_JAVASCRIPT
, IDS_BLOCKED_JAVASCRIPT_UNBLOCK
},
315 {CONTENT_SETTINGS_TYPE_PLUGINS
, IDS_BLOCKED_PLUGINS_UNBLOCK_ALL
},
316 {CONTENT_SETTINGS_TYPE_POPUPS
, IDS_BLOCKED_POPUPS_UNBLOCK
},
317 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER
, IDS_BLOCKED_PPAPI_BROKER_UNBLOCK
},
318 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
, IDS_BLOCKED_DOWNLOAD_UNBLOCK
},
320 // Fields as for kBlockedAllowIDs, above.
321 static const ContentSettingsTypeIdEntry kAllowedAllowIDs
[] = {
322 {CONTENT_SETTINGS_TYPE_COOKIES
, IDS_ALLOWED_COOKIES_NO_ACTION
},
323 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER
, IDS_ALLOWED_PPAPI_BROKER_NO_ACTION
},
324 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
, IDS_ALLOWED_DOWNLOAD_NO_ACTION
},
327 std::string radio_allow_label
;
329 int resource_id
= GetIdForContentType(kAllowedAllowIDs
,
330 arraysize(kAllowedAllowIDs
),
332 radio_allow_label
= l10n_util::GetStringUTF8(resource_id
);
334 radio_allow_label
= l10n_util::GetStringFUTF8(
335 GetIdForContentType(kBlockedAllowIDs
, arraysize(kBlockedAllowIDs
),
340 static const ContentSettingsTypeIdEntry kBlockedBlockIDs
[] = {
341 {CONTENT_SETTINGS_TYPE_COOKIES
, IDS_BLOCKED_COOKIES_NO_ACTION
},
342 {CONTENT_SETTINGS_TYPE_IMAGES
, IDS_BLOCKED_IMAGES_NO_ACTION
},
343 {CONTENT_SETTINGS_TYPE_JAVASCRIPT
, IDS_BLOCKED_JAVASCRIPT_NO_ACTION
},
344 {CONTENT_SETTINGS_TYPE_PLUGINS
, IDS_BLOCKED_PLUGINS_NO_ACTION
},
345 {CONTENT_SETTINGS_TYPE_POPUPS
, IDS_BLOCKED_POPUPS_NO_ACTION
},
346 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER
, IDS_BLOCKED_PPAPI_BROKER_NO_ACTION
},
347 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
, IDS_BLOCKED_DOWNLOAD_NO_ACTION
},
349 static const ContentSettingsTypeIdEntry kAllowedBlockIDs
[] = {
350 {CONTENT_SETTINGS_TYPE_COOKIES
, IDS_ALLOWED_COOKIES_BLOCK
},
351 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER
, IDS_ALLOWED_PPAPI_BROKER_BLOCK
},
352 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
, IDS_ALLOWED_DOWNLOAD_BLOCK
},
355 std::string radio_block_label
;
357 int resource_id
= GetIdForContentType(kAllowedBlockIDs
,
358 arraysize(kAllowedBlockIDs
),
360 radio_block_label
= l10n_util::GetStringFUTF8(resource_id
, display_host
);
362 radio_block_label
= l10n_util::GetStringUTF8(
363 GetIdForContentType(kBlockedBlockIDs
, arraysize(kBlockedBlockIDs
),
367 radio_group
.radio_items
.push_back(radio_allow_label
);
368 radio_group
.radio_items
.push_back(radio_block_label
);
369 ContentSetting setting
;
370 SettingSource setting_source
= SETTING_SOURCE_NONE
;
371 bool setting_is_wildcard
= false;
373 if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES
) {
374 content_settings::CookieSettings
* cookie_settings
=
375 CookieSettingsFactory::GetForProfile(profile()).get();
376 setting
= cookie_settings
->GetCookieSetting(
377 url
, url
, true, &setting_source
);
380 HostContentSettingsMap
* map
= profile()->GetHostContentSettingsMap();
381 scoped_ptr
<base::Value
> value
=
382 map
->GetWebsiteSetting(url
, url
, content_type(), std::string(), &info
);
383 setting
= content_settings::ValueToContentSetting(value
.get());
384 setting_source
= info
.source
;
385 setting_is_wildcard
=
386 info
.primary_pattern
== ContentSettingsPattern::Wildcard() &&
387 info
.secondary_pattern
== ContentSettingsPattern::Wildcard();
390 if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS
&&
391 setting
== CONTENT_SETTING_ALLOW
&&
392 setting_is_wildcard
) {
393 // In the corner case of unrecognized plugins (which are now blocked by
394 // default) we indicate the blocked state in the UI and allow the user to
396 radio_group
.default_item
= 1;
397 } else if (setting
== CONTENT_SETTING_ALLOW
) {
398 radio_group
.default_item
= kAllowButtonIndex
;
399 // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|.
401 radio_group
.default_item
= 1;
402 block_setting_
= setting
;
405 set_setting_is_managed(setting_source
!= SETTING_SOURCE_USER
&&
406 setting
!= CONTENT_SETTING_ASK
);
407 if (setting_source
!= SETTING_SOURCE_USER
) {
408 set_radio_group_enabled(false);
410 set_radio_group_enabled(true);
412 selected_item_
= radio_group
.default_item
;
413 set_radio_group(radio_group
);
416 void ContentSettingSingleRadioGroup::AddException(ContentSetting setting
) {
418 profile()->GetHostContentSettingsMap()->AddExceptionForURL(
419 bubble_content().radio_group
.url
,
420 bubble_content().radio_group
.url
,
426 void ContentSettingSingleRadioGroup::OnRadioClicked(int radio_index
) {
427 selected_item_
= radio_index
;
430 class ContentSettingCookiesBubbleModel
: public ContentSettingSingleRadioGroup
{
432 ContentSettingCookiesBubbleModel(Delegate
* delegate
,
433 WebContents
* web_contents
,
436 ~ContentSettingCookiesBubbleModel() override
;
439 void OnCustomLinkClicked() override
;
442 ContentSettingCookiesBubbleModel::ContentSettingCookiesBubbleModel(
444 WebContents
* web_contents
,
446 : ContentSettingSingleRadioGroup(delegate
,
449 CONTENT_SETTINGS_TYPE_COOKIES
) {
450 set_custom_link_enabled(true);
453 ContentSettingCookiesBubbleModel::~ContentSettingCookiesBubbleModel() {
454 // On some plattforms e.g. MacOS X it is possible to close a tab while the
455 // cookies settings bubble is open. This resets the web contents to NULL.
456 if (settings_changed() && web_contents()) {
457 CollectedCookiesInfoBarDelegate::Create(
458 InfoBarService::FromWebContents(web_contents()));
462 void ContentSettingCookiesBubbleModel::OnCustomLinkClicked() {
465 content::NotificationService::current()->Notify(
466 chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN
,
467 content::Source
<TabSpecificContentSettings
>(
468 TabSpecificContentSettings::FromWebContents(web_contents())),
469 content::NotificationService::NoDetails());
470 delegate()->ShowCollectedCookiesDialog(web_contents());
473 class ContentSettingPluginBubbleModel
: public ContentSettingSingleRadioGroup
{
475 ContentSettingPluginBubbleModel(Delegate
* delegate
,
476 WebContents
* web_contents
,
479 ~ContentSettingPluginBubbleModel() override
;
482 void OnCustomLinkClicked() override
;
485 ContentSettingPluginBubbleModel::ContentSettingPluginBubbleModel(
487 WebContents
* web_contents
,
489 : ContentSettingSingleRadioGroup(delegate
,
492 CONTENT_SETTINGS_TYPE_PLUGINS
) {
493 // Disable the "Run all plugins this time" link if the setting is managed and
494 // can't be controlled by the user or if the user already clicked on the link
495 // and ran all plugins.
496 set_custom_link_enabled(!setting_is_managed() &&
498 TabSpecificContentSettings::FromWebContents(
499 web_contents
)->load_plugins_link_enabled());
500 // Build blocked plugin list.
502 TabSpecificContentSettings
* content_settings
=
503 TabSpecificContentSettings::FromWebContents(web_contents
);
505 const std::vector
<base::string16
>& blocked_plugins
=
506 content_settings
->blocked_plugin_names();
507 for (const base::string16
& blocked_plugin
: blocked_plugins
) {
508 ListItem
plugin_item(
509 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
510 IDR_BLOCKED_PLUGINS
),
511 base::UTF16ToUTF8(blocked_plugin
), false, 0);
512 add_list_item(plugin_item
);
517 ContentSettingPluginBubbleModel::~ContentSettingPluginBubbleModel() {
518 if (settings_changed()) {
519 // If the user elected to allow all plugins then run plugins at this time.
520 if (selected_item() == kAllowButtonIndex
)
521 OnCustomLinkClicked();
525 void ContentSettingPluginBubbleModel::OnCustomLinkClicked() {
526 content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble"));
527 // Web contents can be NULL if the tab was closed while the plugins
528 // settings bubble is visible.
531 #if defined(ENABLE_PLUGINS)
532 // TODO(bauerb): We should send the identifiers of blocked plugins here.
533 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
534 web_contents(), true, std::string());
536 set_custom_link_enabled(false);
537 TabSpecificContentSettings::FromWebContents(web_contents())->
538 set_load_plugins_link_enabled(false);
541 class ContentSettingPopupBubbleModel
: public ContentSettingSingleRadioGroup
{
543 ContentSettingPopupBubbleModel(Delegate
* delegate
,
544 WebContents
* web_contents
,
546 ~ContentSettingPopupBubbleModel() override
{}
549 void OnListItemClicked(int index
) override
;
551 int32
item_id_from_item_index(int index
) const {
552 return bubble_content().list_items
[index
].item_id
;
556 ContentSettingPopupBubbleModel::ContentSettingPopupBubbleModel(
558 WebContents
* web_contents
,
560 : ContentSettingSingleRadioGroup(delegate
,
563 CONTENT_SETTINGS_TYPE_POPUPS
) {
565 // Build blocked popup list.
566 std::map
<int32
, GURL
> blocked_popups
=
567 PopupBlockerTabHelper::FromWebContents(web_contents
)
568 ->GetBlockedPopupRequests();
569 for (const std::pair
<int32
, GURL
>& blocked_popup
: blocked_popups
) {
570 std::string
title(blocked_popup
.second
.spec());
571 // The pop-up may not have a valid URL.
573 title
= l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE
);
574 ListItem
popup_item(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
575 IDR_DEFAULT_FAVICON
),
576 title
, true, blocked_popup
.first
);
577 add_list_item(popup_item
);
582 void ContentSettingPopupBubbleModel::OnListItemClicked(int index
) {
583 if (web_contents()) {
584 PopupBlockerTabHelper::FromWebContents(web_contents())
585 ->ShowBlockedPopup(item_id_from_item_index(index
));
589 // The model of the content settings bubble for media settings.
590 class ContentSettingMediaStreamBubbleModel
591 : public ContentSettingTitleAndLinkModel
{
593 ContentSettingMediaStreamBubbleModel(Delegate
* delegate
,
594 WebContents
* web_contents
,
597 ~ContentSettingMediaStreamBubbleModel() override
;
599 void OnManageLinkClicked() override
;
602 // Helper functions to check if this bubble was invoked for microphone,
603 // camera, or both devices.
604 bool MicrophoneAccessed() const;
605 bool CameraAccessed() const;
608 // Sets the data for the radio buttons of the bubble.
609 void SetRadioGroup();
610 // Sets the data for the media menus of the bubble.
611 void SetMediaMenus();
612 // Set the settings management link.
613 void SetManageLink();
614 void SetCustomLink();
615 // Updates the camera and microphone setting with the passed |setting|.
616 void UpdateSettings(ContentSetting setting
);
617 // Updates the camera and microphone default device with the passed |type|
619 void UpdateDefaultDeviceForType(content::MediaStreamType type
,
620 const std::string
& device
);
622 // ContentSettingBubbleModel implementation.
623 void OnRadioClicked(int radio_index
) override
;
624 void OnMediaMenuClicked(content::MediaStreamType type
,
625 const std::string
& selected_device
) override
;
627 // The index of the selected radio item.
629 // The content settings that are associated with the individual radio
631 ContentSetting radio_item_setting_
[2];
632 // The state of the microphone and camera access.
633 TabSpecificContentSettings::MicrophoneCameraState state_
;
636 ContentSettingMediaStreamBubbleModel::ContentSettingMediaStreamBubbleModel(
638 WebContents
* web_contents
,
640 : ContentSettingTitleAndLinkModel(
641 delegate
, web_contents
, profile
, CONTENT_SETTINGS_TYPE_MEDIASTREAM
),
643 state_(TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED
) {
644 // TODO(msramek): Every bubble is tied to a particular content setting.
645 // The media bubble has three states - mic only, camera only, and both.
646 // However, it is always tied to the deprecated MEDIASTREAM setting. Refactor
647 // this so that it refers to the MIC setting for microphone and CAMERA
648 // setting for camera to reduce the duplication of code in practically every
649 // method. Furthermore, it should be possible not to tie the bubble to any
650 // particular content setting type, as we still need the bubble for both
651 // camera and microphone, but should not use the deprecated MEDIASTREAM
655 // Initialize the content settings associated with the individual radio
657 radio_item_setting_
[0] = CONTENT_SETTING_ASK
;
658 radio_item_setting_
[1] = CONTENT_SETTING_BLOCK
;
660 TabSpecificContentSettings
* content_settings
=
661 TabSpecificContentSettings::FromWebContents(web_contents
);
662 state_
= content_settings
->GetMicrophoneCameraState();
663 DCHECK(CameraAccessed() || MicrophoneAccessed());
672 ContentSettingMediaStreamBubbleModel::~ContentSettingMediaStreamBubbleModel() {
673 // On some platforms (e.g. MacOS X) it is possible to close a tab while the
674 // media stream bubble is open. This resets the web contents to NULL.
678 for (const std::pair
<content::MediaStreamType
, MediaMenu
>& media_menu
:
679 bubble_content().media_menus
) {
680 if (media_menu
.second
.selected_device
.id
!=
681 media_menu
.second
.default_device
.id
) {
682 UpdateDefaultDeviceForType(media_menu
.first
,
683 media_menu
.second
.selected_device
.id
);
687 // Update the media settings if the radio button selection was changed.
688 if (selected_item_
!= bubble_content().radio_group
.default_item
) {
689 UpdateSettings(radio_item_setting_
[selected_item_
]);
693 bool ContentSettingMediaStreamBubbleModel::MicrophoneAccessed() const {
694 return (state_
& TabSpecificContentSettings::MICROPHONE_ACCESSED
) != 0;
697 bool ContentSettingMediaStreamBubbleModel::CameraAccessed() const {
698 return (state_
& TabSpecificContentSettings::CAMERA_ACCESSED
) != 0;
701 void ContentSettingMediaStreamBubbleModel::OnManageLinkClicked() {
705 if (MicrophoneAccessed()) {
706 delegate()->ShowContentSettingsPage(CameraAccessed()
707 ? CONTENT_SETTINGS_TYPE_MEDIASTREAM
708 : CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
);
710 delegate()->ShowContentSettingsPage(
711 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
);
715 void ContentSettingMediaStreamBubbleModel::SetTitle() {
716 DCHECK(CameraAccessed() || MicrophoneAccessed());
718 if (state_
& TabSpecificContentSettings::MICROPHONE_BLOCKED
) {
719 title_id
= (state_
& TabSpecificContentSettings::CAMERA_BLOCKED
) ?
720 IDS_MICROPHONE_CAMERA_BLOCKED
: IDS_MICROPHONE_BLOCKED
;
721 } else if (state_
& TabSpecificContentSettings::CAMERA_BLOCKED
) {
722 title_id
= IDS_CAMERA_BLOCKED
;
723 } else if (MicrophoneAccessed()) {
724 title_id
= CameraAccessed() ? IDS_MICROPHONE_CAMERA_ALLOWED
725 : IDS_MICROPHONE_ACCESSED
;
726 } else if (CameraAccessed()) {
727 title_id
= IDS_CAMERA_ACCESSED
;
729 set_title(l10n_util::GetStringUTF8(title_id
));
732 void ContentSettingMediaStreamBubbleModel::SetRadioGroup() {
733 TabSpecificContentSettings
* content_settings
=
734 TabSpecificContentSettings::FromWebContents(web_contents());
735 GURL url
= content_settings
->media_stream_access_origin();
736 RadioGroup radio_group
;
737 radio_group
.url
= url
;
739 base::string16 display_host_utf16
=
740 url_formatter::FormatUrlForSecurityDisplay(
741 url
, profile()->GetPrefs()->GetString(prefs::kAcceptLanguages
));
742 std::string
display_host(base::UTF16ToUTF8(display_host_utf16
));
743 if (display_host
.empty())
744 display_host
= url
.spec();
746 DCHECK(CameraAccessed() || MicrophoneAccessed());
747 int radio_allow_label_id
= 0;
748 int radio_block_label_id
= 0;
749 if (state_
& (TabSpecificContentSettings::MICROPHONE_BLOCKED
|
750 TabSpecificContentSettings::CAMERA_BLOCKED
)) {
751 if (content::IsOriginSecure(url
)) {
752 radio_item_setting_
[0] = CONTENT_SETTING_ALLOW
;
753 radio_allow_label_id
= IDS_BLOCKED_MEDIASTREAM_CAMERA_ALLOW
;
754 if (MicrophoneAccessed())
755 radio_allow_label_id
= CameraAccessed() ?
756 IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ALLOW
:
757 IDS_BLOCKED_MEDIASTREAM_MIC_ALLOW
;
759 radio_allow_label_id
= IDS_BLOCKED_MEDIASTREAM_CAMERA_ASK
;
760 if (MicrophoneAccessed())
761 radio_allow_label_id
= CameraAccessed() ?
762 IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ASK
:
763 IDS_BLOCKED_MEDIASTREAM_MIC_ASK
;
765 radio_block_label_id
= IDS_BLOCKED_MEDIASTREAM_CAMERA_NO_ACTION
;
766 if (MicrophoneAccessed())
767 radio_block_label_id
= CameraAccessed() ?
768 IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION
:
769 IDS_BLOCKED_MEDIASTREAM_MIC_NO_ACTION
;
771 if (MicrophoneAccessed() && CameraAccessed()) {
772 radio_allow_label_id
= IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION
;
773 radio_block_label_id
= IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_BLOCK
;
774 } else if (MicrophoneAccessed()) {
775 radio_allow_label_id
= IDS_ALLOWED_MEDIASTREAM_MIC_NO_ACTION
;
776 radio_block_label_id
= IDS_ALLOWED_MEDIASTREAM_MIC_BLOCK
;
778 radio_allow_label_id
= IDS_ALLOWED_MEDIASTREAM_CAMERA_NO_ACTION
;
779 radio_block_label_id
= IDS_ALLOWED_MEDIASTREAM_CAMERA_BLOCK
;
783 (MicrophoneAccessed() && content_settings
->IsContentBlocked(
784 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
)) ||
785 (CameraAccessed() && content_settings
->IsContentBlocked(
786 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
)) ? 1 : 0;
788 std::string radio_allow_label
= l10n_util::GetStringFUTF8(
789 radio_allow_label_id
, base::UTF8ToUTF16(display_host
));
790 std::string radio_block_label
=
791 l10n_util::GetStringUTF8(radio_block_label_id
);
793 radio_group
.default_item
= selected_item_
;
794 radio_group
.radio_items
.push_back(radio_allow_label
);
795 radio_group
.radio_items
.push_back(radio_block_label
);
797 set_radio_group(radio_group
);
798 set_radio_group_enabled(true);
801 void ContentSettingMediaStreamBubbleModel::UpdateSettings(
802 ContentSetting setting
) {
804 HostContentSettingsMap
* content_settings
=
805 profile()->GetHostContentSettingsMap();
806 TabSpecificContentSettings
* tab_content_settings
=
807 TabSpecificContentSettings::FromWebContents(web_contents());
808 // The same patterns must be used as in other places (e.g. the infobar) in
809 // order to override the existing rule. Otherwise a new rule is created.
810 // TODO(markusheintz): Extract to a helper so that there is only a single
812 ContentSettingsPattern primary_pattern
=
813 ContentSettingsPattern::FromURLNoWildcard(
814 tab_content_settings
->media_stream_access_origin());
815 ContentSettingsPattern secondary_pattern
=
816 ContentSettingsPattern::Wildcard();
817 if (MicrophoneAccessed()) {
818 content_settings
->SetContentSetting(
819 primary_pattern
, secondary_pattern
,
820 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
, std::string(), setting
);
822 if (CameraAccessed()) {
823 content_settings
->SetContentSetting(
824 primary_pattern
, secondary_pattern
,
825 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
, std::string(), setting
);
830 void ContentSettingMediaStreamBubbleModel::UpdateDefaultDeviceForType(
831 content::MediaStreamType type
,
832 const std::string
& device
) {
833 PrefService
* prefs
= profile()->GetPrefs();
834 if (type
== content::MEDIA_DEVICE_AUDIO_CAPTURE
) {
835 prefs
->SetString(prefs::kDefaultAudioCaptureDevice
, device
);
837 DCHECK_EQ(content::MEDIA_DEVICE_VIDEO_CAPTURE
, type
);
838 prefs
->SetString(prefs::kDefaultVideoCaptureDevice
, device
);
842 void ContentSettingMediaStreamBubbleModel::SetMediaMenus() {
843 TabSpecificContentSettings
* content_settings
=
844 TabSpecificContentSettings::FromWebContents(web_contents());
845 const std::string
& requested_microphone
=
846 content_settings
->media_stream_requested_audio_device();
847 const std::string
& requested_camera
=
848 content_settings
->media_stream_requested_video_device();
850 // Add microphone menu.
851 PrefService
* prefs
= profile()->GetPrefs();
852 MediaCaptureDevicesDispatcher
* dispatcher
=
853 MediaCaptureDevicesDispatcher::GetInstance();
854 const content::MediaStreamDevices
& microphones
=
855 dispatcher
->GetAudioCaptureDevices();
857 if (MicrophoneAccessed()) {
859 mic_menu
.label
= l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_MIC_LABEL
);
860 if (!microphones
.empty()) {
861 std::string preferred_mic
;
862 if (requested_microphone
.empty()) {
863 preferred_mic
= prefs
->GetString(prefs::kDefaultAudioCaptureDevice
);
864 mic_menu
.disabled
= false;
866 // Set the |disabled| to true in order to disable the device selection
867 // menu on the media settings bubble. This must be done if the website
868 // manages the microphone devices itself.
869 preferred_mic
= requested_microphone
;
870 mic_menu
.disabled
= true;
873 mic_menu
.default_device
= GetMediaDeviceById(preferred_mic
, microphones
);
874 mic_menu
.selected_device
= mic_menu
.default_device
;
876 add_media_menu(content::MEDIA_DEVICE_AUDIO_CAPTURE
, mic_menu
);
879 if (CameraAccessed()) {
880 const content::MediaStreamDevices
& cameras
=
881 dispatcher
->GetVideoCaptureDevices();
882 MediaMenu camera_menu
;
884 l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_CAMERA_LABEL
);
885 if (!cameras
.empty()) {
886 std::string preferred_camera
;
887 if (requested_camera
.empty()) {
888 preferred_camera
= prefs
->GetString(prefs::kDefaultVideoCaptureDevice
);
889 camera_menu
.disabled
= false;
891 // Disable the menu since the website is managing the camera devices
893 preferred_camera
= requested_camera
;
894 camera_menu
.disabled
= true;
897 camera_menu
.default_device
=
898 GetMediaDeviceById(preferred_camera
, cameras
);
899 camera_menu
.selected_device
= camera_menu
.default_device
;
901 add_media_menu(content::MEDIA_DEVICE_VIDEO_CAPTURE
, camera_menu
);
905 void ContentSettingMediaStreamBubbleModel::SetManageLink() {
906 // By default, the manage link refers to both media types. We only need
907 // to change the link text if only one media type was accessed.
908 if (CameraAccessed() && MicrophoneAccessed())
911 set_manage_link(l10n_util::GetStringUTF8(MicrophoneAccessed()
912 ? IDS_MEDIASTREAM_MICROPHONE_BUBBLE_MANAGE_LINK
913 : IDS_MEDIASTREAM_CAMERA_BUBBLE_MANAGE_LINK
));
916 void ContentSettingMediaStreamBubbleModel::SetCustomLink() {
917 TabSpecificContentSettings
* content_settings
=
918 TabSpecificContentSettings::FromWebContents(web_contents());
919 if (content_settings
->IsMicrophoneCameraStateChanged()) {
920 set_custom_link(l10n_util::GetStringUTF8(
921 IDS_MEDIASTREAM_SETTING_CHANGED_MESSAGE
));
925 void ContentSettingMediaStreamBubbleModel::OnRadioClicked(int radio_index
) {
926 selected_item_
= radio_index
;
929 void ContentSettingMediaStreamBubbleModel::OnMediaMenuClicked(
930 content::MediaStreamType type
,
931 const std::string
& selected_device_id
) {
932 DCHECK(type
== content::MEDIA_DEVICE_AUDIO_CAPTURE
||
933 type
== content::MEDIA_DEVICE_VIDEO_CAPTURE
);
934 DCHECK_EQ(1U, bubble_content().media_menus
.count(type
));
935 MediaCaptureDevicesDispatcher
* dispatcher
=
936 MediaCaptureDevicesDispatcher::GetInstance();
937 const content::MediaStreamDevices
& devices
=
938 (type
== content::MEDIA_DEVICE_AUDIO_CAPTURE
) ?
939 dispatcher
->GetAudioCaptureDevices() :
940 dispatcher
->GetVideoCaptureDevices();
941 set_selected_device(GetMediaDeviceById(selected_device_id
, devices
));
944 class ContentSettingDomainListBubbleModel
945 : public ContentSettingTitleAndLinkModel
{
947 ContentSettingDomainListBubbleModel(Delegate
* delegate
,
948 WebContents
* web_contents
,
950 ContentSettingsType content_type
);
951 ~ContentSettingDomainListBubbleModel() override
{}
954 void MaybeAddDomainList(const std::set
<std::string
>& hosts
, int title_id
);
955 void SetDomainsAndCustomLink();
956 void OnCustomLinkClicked() override
;
959 ContentSettingDomainListBubbleModel::ContentSettingDomainListBubbleModel(
961 WebContents
* web_contents
,
963 ContentSettingsType content_type
)
964 : ContentSettingTitleAndLinkModel(
965 delegate
, web_contents
, profile
, content_type
) {
966 DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION
, content_type
) <<
967 "SetDomains currently only supports geolocation content type";
968 SetDomainsAndCustomLink();
971 void ContentSettingDomainListBubbleModel::MaybeAddDomainList(
972 const std::set
<std::string
>& hosts
, int title_id
) {
973 if (!hosts
.empty()) {
974 DomainList domain_list
;
975 domain_list
.title
= l10n_util::GetStringUTF8(title_id
);
976 domain_list
.hosts
= hosts
;
977 add_domain_list(domain_list
);
981 void ContentSettingDomainListBubbleModel::SetDomainsAndCustomLink() {
982 TabSpecificContentSettings
* content_settings
=
983 TabSpecificContentSettings::FromWebContents(web_contents());
984 const ContentSettingsUsagesState
& usages
=
985 content_settings
->geolocation_usages_state();
986 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state
;
987 unsigned int tab_state_flags
= 0;
988 usages
.GetDetailedInfo(&formatted_hosts_per_state
, &tab_state_flags
);
989 // Divide the tab's current geolocation users into sets according to their
991 MaybeAddDomainList(formatted_hosts_per_state
[CONTENT_SETTING_ALLOW
],
992 IDS_GEOLOCATION_BUBBLE_SECTION_ALLOWED
);
994 MaybeAddDomainList(formatted_hosts_per_state
[CONTENT_SETTING_BLOCK
],
995 IDS_GEOLOCATION_BUBBLE_SECTION_DENIED
);
997 if (tab_state_flags
& ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION
) {
998 set_custom_link(l10n_util::GetStringUTF8(
999 IDS_GEOLOCATION_BUBBLE_CLEAR_LINK
));
1000 set_custom_link_enabled(true);
1001 } else if (tab_state_flags
&
1002 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED
) {
1003 set_custom_link(l10n_util::GetStringUTF8(
1004 IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR
));
1008 void ContentSettingDomainListBubbleModel::OnCustomLinkClicked() {
1009 if (!web_contents())
1011 // Reset this embedder's entry to default for each of the requesting
1012 // origins currently on the page.
1013 const GURL
& embedder_url
= web_contents()->GetURL();
1014 TabSpecificContentSettings
* content_settings
=
1015 TabSpecificContentSettings::FromWebContents(web_contents());
1016 const ContentSettingsUsagesState::StateMap
& state_map
=
1017 content_settings
->geolocation_usages_state().state_map();
1018 HostContentSettingsMap
* settings_map
=
1019 profile()->GetHostContentSettingsMap();
1021 for (const std::pair
<GURL
, ContentSetting
>& map_entry
: state_map
) {
1022 settings_map
->SetContentSetting(
1023 ContentSettingsPattern::FromURLNoWildcard(map_entry
.first
),
1024 ContentSettingsPattern::FromURLNoWildcard(embedder_url
),
1025 CONTENT_SETTINGS_TYPE_GEOLOCATION
, std::string(),
1026 CONTENT_SETTING_DEFAULT
);
1030 class ContentSettingMixedScriptBubbleModel
1031 : public ContentSettingTitleLinkAndCustomModel
{
1033 ContentSettingMixedScriptBubbleModel(Delegate
* delegate
,
1034 WebContents
* web_contents
,
1037 ~ContentSettingMixedScriptBubbleModel() override
{}
1040 void OnCustomLinkClicked() override
;
1043 ContentSettingMixedScriptBubbleModel::ContentSettingMixedScriptBubbleModel(
1045 WebContents
* web_contents
,
1047 : ContentSettingTitleLinkAndCustomModel(delegate
,
1050 CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
) {
1051 content_settings::RecordMixedScriptAction(
1052 content_settings::MIXED_SCRIPT_ACTION_DISPLAYED_BUBBLE
);
1053 set_custom_link_enabled(true);
1056 void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() {
1057 DCHECK(web_contents());
1058 web_contents()->SendToAllFrames(
1059 new ChromeViewMsg_SetAllowRunningInsecureContent(MSG_ROUTING_NONE
, true));
1060 web_contents()->GetMainFrame()->Send(new ChromeViewMsg_ReloadFrame(
1061 web_contents()->GetMainFrame()->GetRoutingID()));
1063 content_settings::RecordMixedScriptAction(
1064 content_settings::MIXED_SCRIPT_ACTION_CLICKED_ALLOW
);
1065 content_settings::RecordMixedScriptActionWithRAPPOR(
1066 content_settings::MIXED_SCRIPT_ACTION_CLICKED_ALLOW
,
1067 web_contents()->GetLastCommittedURL());
1070 ContentSettingRPHBubbleModel::ContentSettingRPHBubbleModel(
1072 WebContents
* web_contents
,
1074 ProtocolHandlerRegistry
* registry
)
1075 : ContentSettingTitleAndLinkModel(delegate
,
1078 CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS
),
1080 registry_(registry
),
1081 pending_handler_(ProtocolHandler::EmptyProtocolHandler()),
1082 previous_handler_(ProtocolHandler::EmptyProtocolHandler()) {
1083 TabSpecificContentSettings
* content_settings
=
1084 TabSpecificContentSettings::FromWebContents(web_contents
);
1085 pending_handler_
= content_settings
->pending_protocol_handler();
1086 previous_handler_
= content_settings
->previous_protocol_handler();
1088 base::string16 protocol
;
1089 if (pending_handler_
.protocol() == "mailto") {
1090 protocol
= l10n_util::GetStringUTF16(
1091 IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME
);
1092 } else if (pending_handler_
.protocol() == "webcal") {
1093 protocol
= l10n_util::GetStringUTF16(
1094 IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME
);
1096 protocol
= base::UTF8ToUTF16(pending_handler_
.protocol());
1099 // Note that we ignore the |title| parameter.
1100 if (previous_handler_
.IsEmpty()) {
1101 set_title(l10n_util::GetStringFUTF8(
1102 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM
,
1103 base::UTF8ToUTF16(pending_handler_
.url().host()),
1106 set_title(l10n_util::GetStringFUTF8(
1107 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE
,
1108 base::UTF8ToUTF16(pending_handler_
.url().host()),
1110 base::UTF8ToUTF16(previous_handler_
.url().host())));
1113 std::string radio_allow_label
=
1114 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_ACCEPT
);
1115 std::string radio_deny_label
=
1116 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_DENY
);
1117 std::string radio_ignore_label
=
1118 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_IGNORE
);
1120 GURL url
= web_contents
->GetURL();
1121 RadioGroup radio_group
;
1122 radio_group
.url
= url
;
1124 radio_group
.radio_items
.push_back(radio_allow_label
);
1125 radio_group
.radio_items
.push_back(radio_deny_label
);
1126 radio_group
.radio_items
.push_back(radio_ignore_label
);
1127 ContentSetting setting
=
1128 content_settings
->pending_protocol_handler_setting();
1129 if (setting
== CONTENT_SETTING_ALLOW
)
1130 radio_group
.default_item
= RPH_ALLOW
;
1131 else if (setting
== CONTENT_SETTING_BLOCK
)
1132 radio_group
.default_item
= RPH_BLOCK
;
1134 radio_group
.default_item
= RPH_IGNORE
;
1136 selected_item_
= radio_group
.default_item
;
1137 set_radio_group_enabled(true);
1138 set_radio_group(radio_group
);
1141 void ContentSettingRPHBubbleModel::OnRadioClicked(int radio_index
) {
1142 if (selected_item_
== radio_index
)
1145 selected_item_
= radio_index
;
1147 if (radio_index
== RPH_ALLOW
)
1148 RegisterProtocolHandler();
1149 else if (radio_index
== RPH_BLOCK
)
1150 UnregisterProtocolHandler();
1151 else if (radio_index
== RPH_IGNORE
)
1152 IgnoreProtocolHandler();
1157 void ContentSettingRPHBubbleModel::OnDoneClicked() {
1158 // The user has one chance to deal with the RPH content setting UI,
1159 // then we remove it.
1160 TabSpecificContentSettings::FromWebContents(web_contents())->
1161 ClearPendingProtocolHandler();
1162 content::NotificationService::current()->Notify(
1163 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
1164 content::Source
<WebContents
>(web_contents()),
1165 content::NotificationService::NoDetails());
1168 void ContentSettingRPHBubbleModel::RegisterProtocolHandler() {
1169 // A no-op if the handler hasn't been ignored, but needed in case the user
1170 // selects sequences like register/ignore/register.
1171 registry_
->RemoveIgnoredHandler(pending_handler_
);
1173 registry_
->OnAcceptRegisterProtocolHandler(pending_handler_
);
1174 TabSpecificContentSettings::FromWebContents(web_contents())->
1175 set_pending_protocol_handler_setting(CONTENT_SETTING_ALLOW
);
1178 void ContentSettingRPHBubbleModel::UnregisterProtocolHandler() {
1179 registry_
->OnDenyRegisterProtocolHandler(pending_handler_
);
1180 TabSpecificContentSettings::FromWebContents(web_contents())->
1181 set_pending_protocol_handler_setting(CONTENT_SETTING_BLOCK
);
1182 ClearOrSetPreviousHandler();
1185 void ContentSettingRPHBubbleModel::IgnoreProtocolHandler() {
1186 registry_
->OnIgnoreRegisterProtocolHandler(pending_handler_
);
1187 TabSpecificContentSettings::FromWebContents(web_contents())->
1188 set_pending_protocol_handler_setting(CONTENT_SETTING_DEFAULT
);
1189 ClearOrSetPreviousHandler();
1192 void ContentSettingRPHBubbleModel::ClearOrSetPreviousHandler() {
1193 if (previous_handler_
.IsEmpty()) {
1194 registry_
->ClearDefault(pending_handler_
.protocol());
1196 registry_
->OnAcceptRegisterProtocolHandler(previous_handler_
);
1200 class ContentSettingMidiSysExBubbleModel
1201 : public ContentSettingTitleAndLinkModel
{
1203 ContentSettingMidiSysExBubbleModel(Delegate
* delegate
,
1204 WebContents
* web_contents
,
1206 ~ContentSettingMidiSysExBubbleModel() override
{}
1209 void MaybeAddDomainList(const std::set
<std::string
>& hosts
, int title_id
);
1210 void SetDomainsAndCustomLink();
1211 void OnCustomLinkClicked() override
;
1214 ContentSettingMidiSysExBubbleModel::ContentSettingMidiSysExBubbleModel(
1216 WebContents
* web_contents
,
1218 : ContentSettingTitleAndLinkModel(delegate
,
1221 CONTENT_SETTINGS_TYPE_MIDI_SYSEX
) {
1222 SetDomainsAndCustomLink();
1225 void ContentSettingMidiSysExBubbleModel::MaybeAddDomainList(
1226 const std::set
<std::string
>& hosts
, int title_id
) {
1227 if (!hosts
.empty()) {
1228 DomainList domain_list
;
1229 domain_list
.title
= l10n_util::GetStringUTF8(title_id
);
1230 domain_list
.hosts
= hosts
;
1231 add_domain_list(domain_list
);
1235 void ContentSettingMidiSysExBubbleModel::SetDomainsAndCustomLink() {
1236 TabSpecificContentSettings
* content_settings
=
1237 TabSpecificContentSettings::FromWebContents(web_contents());
1238 const ContentSettingsUsagesState
& usages_state
=
1239 content_settings
->midi_usages_state();
1240 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state
;
1241 unsigned int tab_state_flags
= 0;
1242 usages_state
.GetDetailedInfo(&formatted_hosts_per_state
, &tab_state_flags
);
1243 // Divide the tab's current MIDI sysex users into sets according to their
1244 // permission state.
1245 MaybeAddDomainList(formatted_hosts_per_state
[CONTENT_SETTING_ALLOW
],
1246 IDS_MIDI_SYSEX_BUBBLE_ALLOWED
);
1248 MaybeAddDomainList(formatted_hosts_per_state
[CONTENT_SETTING_BLOCK
],
1249 IDS_MIDI_SYSEX_BUBBLE_DENIED
);
1251 if (tab_state_flags
& ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION
) {
1252 set_custom_link(l10n_util::GetStringUTF8(
1253 IDS_MIDI_SYSEX_BUBBLE_CLEAR_LINK
));
1254 set_custom_link_enabled(true);
1255 } else if (tab_state_flags
&
1256 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED
) {
1257 set_custom_link(l10n_util::GetStringUTF8(
1258 IDS_MIDI_SYSEX_BUBBLE_REQUIRE_RELOAD_TO_CLEAR
));
1262 void ContentSettingMidiSysExBubbleModel::OnCustomLinkClicked() {
1263 if (!web_contents())
1265 // Reset this embedder's entry to default for each of the requesting
1266 // origins currently on the page.
1267 const GURL
& embedder_url
= web_contents()->GetURL();
1268 TabSpecificContentSettings
* content_settings
=
1269 TabSpecificContentSettings::FromWebContents(web_contents());
1270 const ContentSettingsUsagesState::StateMap
& state_map
=
1271 content_settings
->midi_usages_state().state_map();
1272 HostContentSettingsMap
* settings_map
=
1273 profile()->GetHostContentSettingsMap();
1275 for (const std::pair
<GURL
, ContentSetting
>& map_entry
: state_map
) {
1276 settings_map
->SetContentSetting(
1277 ContentSettingsPattern::FromURLNoWildcard(map_entry
.first
),
1278 ContentSettingsPattern::FromURLNoWildcard(embedder_url
),
1279 CONTENT_SETTINGS_TYPE_MIDI_SYSEX
, std::string(),
1280 CONTENT_SETTING_DEFAULT
);
1285 const std::set
<ContentSettingsType
>&
1286 ContentSettingBubbleModel::GetSupportedBubbleTypes() {
1287 CR_DEFINE_STATIC_LOCAL(
1288 const std::set
<ContentSettingsType
>, supported_bubble_types
,
1289 (kSupportedBubbleTypes
,
1290 kSupportedBubbleTypes
+ arraysize(kSupportedBubbleTypes
)));
1291 return supported_bubble_types
;
1295 ContentSettingBubbleModel
*
1296 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
1298 WebContents
* web_contents
,
1300 ContentSettingsType content_type
) {
1301 DCHECK(ContainsKey(GetSupportedBubbleTypes(), content_type
));
1302 if (content_type
== CONTENT_SETTINGS_TYPE_COOKIES
) {
1303 return new ContentSettingCookiesBubbleModel(delegate
, web_contents
,
1306 if (content_type
== CONTENT_SETTINGS_TYPE_POPUPS
) {
1307 return new ContentSettingPopupBubbleModel(delegate
, web_contents
, profile
);
1309 if (content_type
== CONTENT_SETTINGS_TYPE_GEOLOCATION
) {
1310 return new ContentSettingDomainListBubbleModel(delegate
, web_contents
,
1311 profile
, content_type
);
1313 if (content_type
== CONTENT_SETTINGS_TYPE_MEDIASTREAM
) {
1314 return new ContentSettingMediaStreamBubbleModel(delegate
, web_contents
,
1317 if (content_type
== CONTENT_SETTINGS_TYPE_PLUGINS
) {
1318 return new ContentSettingPluginBubbleModel(delegate
, web_contents
, profile
);
1320 if (content_type
== CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
) {
1321 return new ContentSettingMixedScriptBubbleModel(delegate
, web_contents
,
1324 if (content_type
== CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS
) {
1325 ProtocolHandlerRegistry
* registry
=
1326 ProtocolHandlerRegistryFactory::GetForBrowserContext(profile
);
1327 return new ContentSettingRPHBubbleModel(delegate
, web_contents
, profile
,
1330 if (content_type
== CONTENT_SETTINGS_TYPE_MIDI_SYSEX
) {
1331 return new ContentSettingMidiSysExBubbleModel(delegate
, web_contents
,
1334 return new ContentSettingSingleRadioGroup(delegate
, web_contents
, profile
,
1338 ContentSettingBubbleModel::ContentSettingBubbleModel(
1339 WebContents
* web_contents
,
1341 ContentSettingsType content_type
)
1342 : web_contents_(web_contents
),
1344 content_type_(content_type
),
1345 setting_is_managed_(false) {
1346 registrar_
.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED
,
1347 content::Source
<WebContents
>(web_contents
));
1348 registrar_
.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED
,
1349 content::Source
<Profile
>(profile_
));
1352 ContentSettingBubbleModel::~ContentSettingBubbleModel() {
1355 ContentSettingBubbleModel::RadioGroup::RadioGroup() : default_item(0) {}
1357 ContentSettingBubbleModel::RadioGroup::~RadioGroup() {}
1359 ContentSettingBubbleModel::DomainList::DomainList() {}
1361 ContentSettingBubbleModel::DomainList::~DomainList() {}
1363 ContentSettingBubbleModel::MediaMenu::MediaMenu() : disabled(false) {}
1365 ContentSettingBubbleModel::MediaMenu::~MediaMenu() {}
1367 ContentSettingBubbleModel::BubbleContent::BubbleContent()
1368 : radio_group_enabled(false),
1369 custom_link_enabled(false) {
1372 ContentSettingBubbleModel::BubbleContent::~BubbleContent() {}
1374 void ContentSettingBubbleModel::Observe(
1376 const content::NotificationSource
& source
,
1377 const content::NotificationDetails
& details
) {
1378 if (type
== content::NOTIFICATION_WEB_CONTENTS_DESTROYED
) {
1379 DCHECK_EQ(web_contents_
,
1380 content::Source
<WebContents
>(source
).ptr());
1381 web_contents_
= NULL
;
1383 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED
, type
);
1384 DCHECK_EQ(profile_
, content::Source
<Profile
>(source
).ptr());