Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / ui / content_settings / content_setting_bubble_model.cc
blobab1da3c582ca265d3bd2e35355888e272e578d11
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;
56 namespace {
58 const int kAllowButtonIndex = 0;
60 // static
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.
78 enum RPHState {
79 RPH_ALLOW = 0,
80 RPH_BLOCK,
81 RPH_IGNORE,
84 struct ContentSettingsTypeIdEntry {
85 ContentSettingsType type;
86 int id;
89 int GetIdForContentType(const ContentSettingsTypeIdEntry* entries,
90 size_t num_entries,
91 ContentSettingsType type) {
92 for (size_t i = 0; i < num_entries; ++i) {
93 if (entries[i].type == type)
94 return entries[i].id;
96 return 0;
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)
105 return device;
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
110 // device.
111 return *devices.begin();
114 } // namespace
116 ContentSettingTitleAndLinkModel::ContentSettingTitleAndLinkModel(
117 Delegate* delegate,
118 WebContents* web_contents,
119 Profile* profile,
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);
125 SetTitle();
126 SetManageLink();
127 SetLearnMoreLink();
130 void ContentSettingTitleAndLinkModel::SetTitle() {
131 TabSpecificContentSettings* content_settings = NULL;
132 if (web_contents()) {
133 content_settings =
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);
162 int title_id =
163 GetIdForContentType(title_ids, num_title_ids, content_type());
164 if (title_id)
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() {
188 if (delegate_)
189 delegate_->ShowContentSettingsPage(content_type());
192 void ContentSettingTitleAndLinkModel::SetLearnMoreLink() {
193 static const ContentSettingsTypeIdEntry kLearnMoreIDs[] = {
194 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_LEARN_MORE},
196 int learn_more_id =
197 GetIdForContentType(kLearnMoreIDs, arraysize(kLearnMoreIDs),
198 content_type());
199 if (learn_more_id)
200 set_learn_more_link(l10n_util::GetStringUTF8(learn_more_id));
203 void ContentSettingTitleAndLinkModel::OnLearnMoreLinkClicked() {
204 if (delegate_)
205 delegate_->ShowLearnMorePage(content_type());
208 class ContentSettingTitleLinkAndCustomModel
209 : public ContentSettingTitleAndLinkModel {
210 public:
211 ContentSettingTitleLinkAndCustomModel(Delegate* delegate,
212 WebContents* web_contents,
213 Profile* profile,
214 ContentSettingsType content_type);
215 ~ContentSettingTitleLinkAndCustomModel() override {}
217 private:
218 void SetCustomLink();
219 void OnCustomLinkClicked() override {}
222 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel(
223 Delegate* delegate,
224 WebContents* web_contents,
225 Profile* profile,
226 ContentSettingsType content_type)
227 : ContentSettingTitleAndLinkModel(
228 delegate, web_contents, profile, content_type) {
229 SetCustomLink();
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},
238 int custom_link_id =
239 GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type());
240 if (custom_link_id)
241 set_custom_link(l10n_util::GetStringUTF8(custom_link_id));
244 class ContentSettingSingleRadioGroup
245 : public ContentSettingTitleLinkAndCustomModel {
246 public:
247 ContentSettingSingleRadioGroup(Delegate* delegate,
248 WebContents* web_contents,
249 Profile* profile,
250 ContentSettingsType content_type);
251 ~ContentSettingSingleRadioGroup() override;
253 protected:
254 bool settings_changed() const;
255 int selected_item() const { return selected_item_; }
257 private:
258 void SetRadioGroup();
259 void AddException(ContentSetting setting);
260 void OnRadioClicked(int radio_index) override;
262 ContentSetting block_setting_;
263 int selected_item_;
266 ContentSettingSingleRadioGroup::ContentSettingSingleRadioGroup(
267 Delegate* delegate,
268 WebContents* web_contents,
269 Profile* profile,
270 ContentSettingsType content_type)
271 : ContentSettingTitleLinkAndCustomModel(delegate, web_contents, profile,
272 content_type),
273 block_setting_(CONTENT_SETTING_BLOCK),
274 selected_item_(0) {
275 SetRadioGroup();
278 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() {
279 if (settings_changed()) {
280 ContentSetting setting =
281 selected_item_ == kAllowButtonIndex ?
282 CONTENT_SETTING_ALLOW :
283 block_setting_;
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());
303 bool allowed =
304 !content_settings->IsContentBlocked(content_type());
305 DCHECK(!allowed ||
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;
328 if (allowed) {
329 int resource_id = GetIdForContentType(kAllowedAllowIDs,
330 arraysize(kAllowedAllowIDs),
331 content_type());
332 radio_allow_label = l10n_util::GetStringUTF8(resource_id);
333 } else {
334 radio_allow_label = l10n_util::GetStringFUTF8(
335 GetIdForContentType(kBlockedAllowIDs, arraysize(kBlockedAllowIDs),
336 content_type()),
337 display_host);
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;
356 if (allowed) {
357 int resource_id = GetIdForContentType(kAllowedBlockIDs,
358 arraysize(kAllowedBlockIDs),
359 content_type());
360 radio_block_label = l10n_util::GetStringFUTF8(resource_id, display_host);
361 } else {
362 radio_block_label = l10n_util::GetStringUTF8(
363 GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs),
364 content_type()));
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);
378 } else {
379 SettingInfo info;
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
395 // whitelist.
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|.
400 } else {
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);
409 } else {
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) {
417 if (profile()) {
418 profile()->GetHostContentSettingsMap()->AddExceptionForURL(
419 bubble_content().radio_group.url,
420 bubble_content().radio_group.url,
421 content_type(),
422 setting);
426 void ContentSettingSingleRadioGroup::OnRadioClicked(int radio_index) {
427 selected_item_ = radio_index;
430 class ContentSettingCookiesBubbleModel : public ContentSettingSingleRadioGroup {
431 public:
432 ContentSettingCookiesBubbleModel(Delegate* delegate,
433 WebContents* web_contents,
434 Profile* profile);
436 ~ContentSettingCookiesBubbleModel() override;
438 private:
439 void OnCustomLinkClicked() override;
442 ContentSettingCookiesBubbleModel::ContentSettingCookiesBubbleModel(
443 Delegate* delegate,
444 WebContents* web_contents,
445 Profile* profile)
446 : ContentSettingSingleRadioGroup(delegate,
447 web_contents,
448 profile,
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() {
463 if (!web_contents())
464 return;
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 {
474 public:
475 ContentSettingPluginBubbleModel(Delegate* delegate,
476 WebContents* web_contents,
477 Profile* profile);
479 ~ContentSettingPluginBubbleModel() override;
481 private:
482 void OnCustomLinkClicked() override;
485 ContentSettingPluginBubbleModel::ContentSettingPluginBubbleModel(
486 Delegate* delegate,
487 WebContents* web_contents,
488 Profile* profile)
489 : ContentSettingSingleRadioGroup(delegate,
490 web_contents,
491 profile,
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() &&
497 web_contents &&
498 TabSpecificContentSettings::FromWebContents(
499 web_contents)->load_plugins_link_enabled());
500 // Build blocked plugin list.
501 if (web_contents) {
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.
529 if (!web_contents())
530 return;
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());
535 #endif
536 set_custom_link_enabled(false);
537 TabSpecificContentSettings::FromWebContents(web_contents())->
538 set_load_plugins_link_enabled(false);
541 class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup {
542 public:
543 ContentSettingPopupBubbleModel(Delegate* delegate,
544 WebContents* web_contents,
545 Profile* profile);
546 ~ContentSettingPopupBubbleModel() override {}
548 private:
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(
557 Delegate* delegate,
558 WebContents* web_contents,
559 Profile* profile)
560 : ContentSettingSingleRadioGroup(delegate,
561 web_contents,
562 profile,
563 CONTENT_SETTINGS_TYPE_POPUPS) {
564 if (web_contents) {
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.
572 if (title.empty())
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 {
592 public:
593 ContentSettingMediaStreamBubbleModel(Delegate* delegate,
594 WebContents* web_contents,
595 Profile* profile);
597 ~ContentSettingMediaStreamBubbleModel() override;
599 void OnManageLinkClicked() override;
601 private:
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;
607 void SetTitle();
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|
618 // and device.
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.
628 int selected_item_;
629 // The content settings that are associated with the individual radio
630 // buttons.
631 ContentSetting radio_item_setting_[2];
632 // The state of the microphone and camera access.
633 TabSpecificContentSettings::MicrophoneCameraState state_;
636 ContentSettingMediaStreamBubbleModel::ContentSettingMediaStreamBubbleModel(
637 Delegate* delegate,
638 WebContents* web_contents,
639 Profile* profile)
640 : ContentSettingTitleAndLinkModel(
641 delegate, web_contents, profile, CONTENT_SETTINGS_TYPE_MEDIASTREAM),
642 selected_item_(0),
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
652 // setting.
654 DCHECK(profile);
655 // Initialize the content settings associated with the individual radio
656 // buttons.
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());
665 SetTitle();
666 SetRadioGroup();
667 SetMediaMenus();
668 SetManageLink();
669 SetCustomLink();
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.
675 if (!web_contents())
676 return;
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() {
702 if (!delegate())
703 return;
705 if (MicrophoneAccessed()) {
706 delegate()->ShowContentSettingsPage(CameraAccessed()
707 ? CONTENT_SETTINGS_TYPE_MEDIASTREAM
708 : CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
709 } else {
710 delegate()->ShowContentSettingsPage(
711 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
715 void ContentSettingMediaStreamBubbleModel::SetTitle() {
716 DCHECK(CameraAccessed() || MicrophoneAccessed());
717 int title_id = 0;
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;
758 } else {
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;
770 } else {
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;
777 } else {
778 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_NO_ACTION;
779 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_BLOCK;
782 selected_item_ =
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) {
803 if (profile()) {
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
811 // place to touch.
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);
836 } else {
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()) {
858 MediaMenu mic_menu;
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;
865 } else {
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;
883 camera_menu.label =
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;
890 } else {
891 // Disable the menu since the website is managing the camera devices
892 // itself.
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())
909 return;
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 {
946 public:
947 ContentSettingDomainListBubbleModel(Delegate* delegate,
948 WebContents* web_contents,
949 Profile* profile,
950 ContentSettingsType content_type);
951 ~ContentSettingDomainListBubbleModel() override {}
953 private:
954 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
955 void SetDomainsAndCustomLink();
956 void OnCustomLinkClicked() override;
959 ContentSettingDomainListBubbleModel::ContentSettingDomainListBubbleModel(
960 Delegate* delegate,
961 WebContents* web_contents,
962 Profile* profile,
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
990 // permission state.
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())
1010 return;
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 {
1032 public:
1033 ContentSettingMixedScriptBubbleModel(Delegate* delegate,
1034 WebContents* web_contents,
1035 Profile* profile);
1037 ~ContentSettingMixedScriptBubbleModel() override {}
1039 private:
1040 void OnCustomLinkClicked() override;
1043 ContentSettingMixedScriptBubbleModel::ContentSettingMixedScriptBubbleModel(
1044 Delegate* delegate,
1045 WebContents* web_contents,
1046 Profile* profile)
1047 : ContentSettingTitleLinkAndCustomModel(delegate,
1048 web_contents,
1049 profile,
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(
1071 Delegate* delegate,
1072 WebContents* web_contents,
1073 Profile* profile,
1074 ProtocolHandlerRegistry* registry)
1075 : ContentSettingTitleAndLinkModel(delegate,
1076 web_contents,
1077 profile,
1078 CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS),
1079 selected_item_(0),
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);
1095 } else {
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()),
1104 protocol));
1105 } else {
1106 set_title(l10n_util::GetStringFUTF8(
1107 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE,
1108 base::UTF8ToUTF16(pending_handler_.url().host()),
1109 protocol,
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;
1133 else
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)
1143 return;
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();
1153 else
1154 NOTREACHED();
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());
1195 } else {
1196 registry_->OnAcceptRegisterProtocolHandler(previous_handler_);
1200 class ContentSettingMidiSysExBubbleModel
1201 : public ContentSettingTitleAndLinkModel {
1202 public:
1203 ContentSettingMidiSysExBubbleModel(Delegate* delegate,
1204 WebContents* web_contents,
1205 Profile* profile);
1206 ~ContentSettingMidiSysExBubbleModel() override {}
1208 private:
1209 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
1210 void SetDomainsAndCustomLink();
1211 void OnCustomLinkClicked() override;
1214 ContentSettingMidiSysExBubbleModel::ContentSettingMidiSysExBubbleModel(
1215 Delegate* delegate,
1216 WebContents* web_contents,
1217 Profile* profile)
1218 : ContentSettingTitleAndLinkModel(delegate,
1219 web_contents,
1220 profile,
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())
1264 return;
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);
1284 // static
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;
1294 // static
1295 ContentSettingBubbleModel*
1296 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
1297 Delegate* delegate,
1298 WebContents* web_contents,
1299 Profile* profile,
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,
1304 profile);
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,
1315 profile);
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,
1322 profile);
1324 if (content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
1325 ProtocolHandlerRegistry* registry =
1326 ProtocolHandlerRegistryFactory::GetForBrowserContext(profile);
1327 return new ContentSettingRPHBubbleModel(delegate, web_contents, profile,
1328 registry);
1330 if (content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
1331 return new ContentSettingMidiSysExBubbleModel(delegate, web_contents,
1332 profile);
1334 return new ContentSettingSingleRadioGroup(delegate, web_contents, profile,
1335 content_type);
1338 ContentSettingBubbleModel::ContentSettingBubbleModel(
1339 WebContents* web_contents,
1340 Profile* profile,
1341 ContentSettingsType content_type)
1342 : web_contents_(web_contents),
1343 profile_(profile),
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(
1375 int type,
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;
1382 } else {
1383 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
1384 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
1385 profile_ = NULL;