Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / ui / content_settings / content_setting_bubble_model.cc
blob0a03d05ad5f14ab38aa8f247ab791d484620f641
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/prefs/pref_service.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/content_settings/chrome_content_settings_utils.h"
12 #include "chrome/browser/content_settings/cookie_settings_factory.h"
13 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
14 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
15 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
16 #include "chrome/browser/infobars/infobar_service.h"
17 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
18 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
21 #include "chrome/browser/ui/browser_navigator.h"
22 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
23 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/render_messages.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "components/content_settings/content/common/content_settings_messages.h"
29 #include "components/content_settings/core/browser/content_settings_utils.h"
30 #include "components/content_settings/core/browser/cookie_settings.h"
31 #include "components/content_settings/core/common/content_settings.h"
32 #include "components/url_formatter/elide_url.h"
33 #include "content/public/browser/notification_service.h"
34 #include "content/public/browser/render_frame_host.h"
35 #include "content/public/browser/render_process_host.h"
36 #include "content/public/browser/render_view_host.h"
37 #include "content/public/browser/user_metrics.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_contents_delegate.h"
40 #include "content/public/common/origin_util.h"
41 #include "grit/components_strings.h"
42 #include "grit/theme_resources.h"
43 #include "ui/base/l10n/l10n_util.h"
44 #include "ui/base/resource/resource_bundle.h"
45 #include "ui/resources/grit/ui_resources.h"
47 using base::UserMetricsAction;
48 using content::WebContents;
49 using content_settings::SettingInfo;
50 using content_settings::SettingSource;
51 using content_settings::SETTING_SOURCE_USER;
52 using content_settings::SETTING_SOURCE_NONE;
54 namespace {
56 const int kAllowButtonIndex = 0;
58 // These states must match the order of appearance of the radio buttons
59 // in the XIB file for the Mac port.
60 enum RPHState {
61 RPH_ALLOW = 0,
62 RPH_BLOCK,
63 RPH_IGNORE,
66 struct ContentSettingsTypeIdEntry {
67 ContentSettingsType type;
68 int id;
71 int GetIdForContentType(const ContentSettingsTypeIdEntry* entries,
72 size_t num_entries,
73 ContentSettingsType type) {
74 for (size_t i = 0; i < num_entries; ++i) {
75 if (entries[i].type == type)
76 return entries[i].id;
78 return 0;
81 const content::MediaStreamDevice& GetMediaDeviceById(
82 const std::string& device_id,
83 const content::MediaStreamDevices& devices) {
84 DCHECK(!devices.empty());
85 for (const content::MediaStreamDevice& device : devices) {
86 if (device.id == device_id)
87 return device;
90 // A device with the |device_id| was not found. It is likely that the device
91 // has been unplugged from the OS. Return the first device as the default
92 // device.
93 return *devices.begin();
96 } // namespace
98 ContentSettingTitleAndLinkModel::ContentSettingTitleAndLinkModel(
99 Delegate* delegate,
100 WebContents* web_contents,
101 Profile* profile,
102 ContentSettingsType content_type)
103 : ContentSettingBubbleModel(web_contents, profile, content_type),
104 delegate_(delegate) {
105 // Notifications do not have a bubble.
106 DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
107 SetTitle();
108 SetManageLink();
109 SetLearnMoreLink();
112 void ContentSettingTitleAndLinkModel::SetTitle() {
113 TabSpecificContentSettings* content_settings = NULL;
114 if (web_contents()) {
115 content_settings =
116 TabSpecificContentSettings::FromWebContents(web_contents());
119 static const ContentSettingsTypeIdEntry kBlockedTitleIDs[] = {
120 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE},
121 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE},
122 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE},
123 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_TITLE},
124 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TITLE},
125 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
126 IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT},
127 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
128 IDS_BLOCKED_PPAPI_BROKER_TITLE},
129 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_TITLE},
131 // Fields as for kBlockedTitleIDs, above.
132 static const ContentSettingsTypeIdEntry kAccessedTitleIDs[] = {
133 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_TITLE},
134 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_TITLE},
135 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_TITLE},
137 const ContentSettingsTypeIdEntry *title_ids = kBlockedTitleIDs;
138 size_t num_title_ids = arraysize(kBlockedTitleIDs);
139 if (content_settings && content_settings->IsContentAllowed(content_type()) &&
140 !content_settings->IsContentBlocked(content_type())) {
141 title_ids = kAccessedTitleIDs;
142 num_title_ids = arraysize(kAccessedTitleIDs);
144 int title_id =
145 GetIdForContentType(title_ids, num_title_ids, content_type());
146 if (title_id)
147 set_title(l10n_util::GetStringUTF8(title_id));
150 void ContentSettingTitleAndLinkModel::SetManageLink() {
151 static const ContentSettingsTypeIdEntry kLinkIDs[] = {
152 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_LINK},
153 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_LINK},
154 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_LINK},
155 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LINK},
156 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_LINK},
157 {CONTENT_SETTINGS_TYPE_GEOLOCATION, IDS_GEOLOCATION_BUBBLE_MANAGE_LINK},
158 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_LEARN_MORE},
159 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, IDS_HANDLERS_BUBBLE_MANAGE_LINK},
160 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, IDS_MEDIASTREAM_BUBBLE_MANAGE_LINK},
161 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_PPAPI_BROKER_BUBBLE_MANAGE_LINK},
162 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOADS_LINK},
163 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, IDS_MIDI_SYSEX_BUBBLE_MANAGE_LINK},
165 set_manage_link(l10n_util::GetStringUTF8(
166 GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type())));
169 void ContentSettingTitleAndLinkModel::OnManageLinkClicked() {
170 if (delegate_)
171 delegate_->ShowContentSettingsPage(content_type());
174 void ContentSettingTitleAndLinkModel::SetLearnMoreLink() {
175 static const ContentSettingsTypeIdEntry kLearnMoreIDs[] = {
176 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_LEARN_MORE},
178 int learn_more_id =
179 GetIdForContentType(kLearnMoreIDs, arraysize(kLearnMoreIDs),
180 content_type());
181 if (learn_more_id)
182 set_learn_more_link(l10n_util::GetStringUTF8(learn_more_id));
185 void ContentSettingTitleAndLinkModel::OnLearnMoreLinkClicked() {
186 if (delegate_)
187 delegate_->ShowLearnMorePage(content_type());
190 class ContentSettingTitleLinkAndCustomModel
191 : public ContentSettingTitleAndLinkModel {
192 public:
193 ContentSettingTitleLinkAndCustomModel(Delegate* delegate,
194 WebContents* web_contents,
195 Profile* profile,
196 ContentSettingsType content_type);
197 ~ContentSettingTitleLinkAndCustomModel() override {}
199 private:
200 void SetCustomLink();
201 void OnCustomLinkClicked() override {}
204 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel(
205 Delegate* delegate,
206 WebContents* web_contents,
207 Profile* profile,
208 ContentSettingsType content_type)
209 : ContentSettingTitleAndLinkModel(
210 delegate, web_contents, profile, content_type) {
211 SetCustomLink();
214 void ContentSettingTitleLinkAndCustomModel::SetCustomLink() {
215 static const ContentSettingsTypeIdEntry kCustomIDs[] = {
216 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO},
217 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL},
218 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_ALLOW_INSECURE_CONTENT_BUTTON},
220 int custom_link_id =
221 GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type());
222 if (custom_link_id)
223 set_custom_link(l10n_util::GetStringUTF8(custom_link_id));
226 class ContentSettingSingleRadioGroup
227 : public ContentSettingTitleLinkAndCustomModel {
228 public:
229 ContentSettingSingleRadioGroup(Delegate* delegate,
230 WebContents* web_contents,
231 Profile* profile,
232 ContentSettingsType content_type);
233 ~ContentSettingSingleRadioGroup() override;
235 protected:
236 bool settings_changed() const;
237 int selected_item() const { return selected_item_; }
239 private:
240 void SetRadioGroup();
241 void AddException(ContentSetting setting);
242 void OnRadioClicked(int radio_index) override;
244 ContentSetting block_setting_;
245 int selected_item_;
248 ContentSettingSingleRadioGroup::ContentSettingSingleRadioGroup(
249 Delegate* delegate,
250 WebContents* web_contents,
251 Profile* profile,
252 ContentSettingsType content_type)
253 : ContentSettingTitleLinkAndCustomModel(delegate, web_contents, profile,
254 content_type),
255 block_setting_(CONTENT_SETTING_BLOCK),
256 selected_item_(0) {
257 SetRadioGroup();
260 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() {
261 if (settings_changed()) {
262 ContentSetting setting =
263 selected_item_ == kAllowButtonIndex ?
264 CONTENT_SETTING_ALLOW :
265 block_setting_;
266 AddException(setting);
270 bool ContentSettingSingleRadioGroup::settings_changed() const {
271 return selected_item_ != bubble_content().radio_group.default_item;
274 // Initialize the radio group by setting the appropriate labels for the
275 // content type and setting the default value based on the content setting.
276 void ContentSettingSingleRadioGroup::SetRadioGroup() {
277 GURL url = web_contents()->GetURL();
278 base::string16 display_host = url_formatter::FormatUrlForSecurityDisplay(
279 url, profile()->GetPrefs()->GetString(prefs::kAcceptLanguages));
280 if (display_host.empty())
281 display_host = base::ASCIIToUTF16(url.spec());
283 TabSpecificContentSettings* content_settings =
284 TabSpecificContentSettings::FromWebContents(web_contents());
285 bool allowed =
286 !content_settings->IsContentBlocked(content_type());
287 DCHECK(!allowed ||
288 content_settings->IsContentAllowed(content_type()));
290 RadioGroup radio_group;
291 radio_group.url = url;
293 static const ContentSettingsTypeIdEntry kBlockedAllowIDs[] = {
294 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK},
295 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_UNBLOCK},
296 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_UNBLOCK},
297 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_UNBLOCK_ALL},
298 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_UNBLOCK},
299 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_UNBLOCK},
300 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_UNBLOCK},
302 // Fields as for kBlockedAllowIDs, above.
303 static const ContentSettingsTypeIdEntry kAllowedAllowIDs[] = {
304 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ALLOWED_COOKIES_NO_ACTION},
305 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_NO_ACTION},
306 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_NO_ACTION},
309 std::string radio_allow_label;
310 if (allowed) {
311 int resource_id = GetIdForContentType(kAllowedAllowIDs,
312 arraysize(kAllowedAllowIDs),
313 content_type());
314 radio_allow_label = l10n_util::GetStringUTF8(resource_id);
315 } else {
316 radio_allow_label = l10n_util::GetStringFUTF8(
317 GetIdForContentType(kBlockedAllowIDs, arraysize(kBlockedAllowIDs),
318 content_type()),
319 display_host);
322 static const ContentSettingsTypeIdEntry kBlockedBlockIDs[] = {
323 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION},
324 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_NO_ACTION},
325 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_NO_ACTION},
326 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_NO_ACTION},
327 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_NO_ACTION},
328 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_NO_ACTION},
329 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_NO_ACTION},
331 static const ContentSettingsTypeIdEntry kAllowedBlockIDs[] = {
332 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ALLOWED_COOKIES_BLOCK},
333 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_BLOCK},
334 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_BLOCK},
337 std::string radio_block_label;
338 if (allowed) {
339 int resource_id = GetIdForContentType(kAllowedBlockIDs,
340 arraysize(kAllowedBlockIDs),
341 content_type());
342 radio_block_label = l10n_util::GetStringFUTF8(resource_id, display_host);
343 } else {
344 radio_block_label = l10n_util::GetStringUTF8(
345 GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs),
346 content_type()));
349 radio_group.radio_items.push_back(radio_allow_label);
350 radio_group.radio_items.push_back(radio_block_label);
351 ContentSetting setting;
352 SettingSource setting_source = SETTING_SOURCE_NONE;
353 bool setting_is_wildcard = false;
355 if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) {
356 content_settings::CookieSettings* cookie_settings =
357 CookieSettingsFactory::GetForProfile(profile()).get();
358 setting = cookie_settings->GetCookieSetting(
359 url, url, true, &setting_source);
360 } else {
361 SettingInfo info;
362 HostContentSettingsMap* map = profile()->GetHostContentSettingsMap();
363 scoped_ptr<base::Value> value =
364 map->GetWebsiteSetting(url, url, content_type(), std::string(), &info);
365 setting = content_settings::ValueToContentSetting(value.get());
366 setting_source = info.source;
367 setting_is_wildcard =
368 info.primary_pattern == ContentSettingsPattern::Wildcard() &&
369 info.secondary_pattern == ContentSettingsPattern::Wildcard();
372 if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS &&
373 setting == CONTENT_SETTING_ALLOW &&
374 setting_is_wildcard) {
375 // In the corner case of unrecognized plugins (which are now blocked by
376 // default) we indicate the blocked state in the UI and allow the user to
377 // whitelist.
378 radio_group.default_item = 1;
379 } else if (setting == CONTENT_SETTING_ALLOW) {
380 radio_group.default_item = kAllowButtonIndex;
381 // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|.
382 } else {
383 radio_group.default_item = 1;
384 block_setting_ = setting;
387 set_setting_is_managed(setting_source != SETTING_SOURCE_USER &&
388 setting != CONTENT_SETTING_ASK);
389 if (setting_source != SETTING_SOURCE_USER) {
390 set_radio_group_enabled(false);
391 } else {
392 set_radio_group_enabled(true);
394 selected_item_ = radio_group.default_item;
395 set_radio_group(radio_group);
398 void ContentSettingSingleRadioGroup::AddException(ContentSetting setting) {
399 if (profile()) {
400 profile()->GetHostContentSettingsMap()->AddExceptionForURL(
401 bubble_content().radio_group.url,
402 bubble_content().radio_group.url,
403 content_type(),
404 setting);
408 void ContentSettingSingleRadioGroup::OnRadioClicked(int radio_index) {
409 selected_item_ = radio_index;
412 class ContentSettingCookiesBubbleModel : public ContentSettingSingleRadioGroup {
413 public:
414 ContentSettingCookiesBubbleModel(Delegate* delegate,
415 WebContents* web_contents,
416 Profile* profile);
418 ~ContentSettingCookiesBubbleModel() override;
420 private:
421 void OnCustomLinkClicked() override;
424 ContentSettingCookiesBubbleModel::ContentSettingCookiesBubbleModel(
425 Delegate* delegate,
426 WebContents* web_contents,
427 Profile* profile)
428 : ContentSettingSingleRadioGroup(delegate,
429 web_contents,
430 profile,
431 CONTENT_SETTINGS_TYPE_COOKIES) {
432 set_custom_link_enabled(true);
435 ContentSettingCookiesBubbleModel::~ContentSettingCookiesBubbleModel() {
436 // On some plattforms e.g. MacOS X it is possible to close a tab while the
437 // cookies settings bubble is open. This resets the web contents to NULL.
438 if (settings_changed() && web_contents()) {
439 CollectedCookiesInfoBarDelegate::Create(
440 InfoBarService::FromWebContents(web_contents()));
444 void ContentSettingCookiesBubbleModel::OnCustomLinkClicked() {
445 if (!web_contents())
446 return;
447 content::NotificationService::current()->Notify(
448 chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN,
449 content::Source<TabSpecificContentSettings>(
450 TabSpecificContentSettings::FromWebContents(web_contents())),
451 content::NotificationService::NoDetails());
452 delegate()->ShowCollectedCookiesDialog(web_contents());
455 class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup {
456 public:
457 ContentSettingPluginBubbleModel(Delegate* delegate,
458 WebContents* web_contents,
459 Profile* profile);
461 ~ContentSettingPluginBubbleModel() override;
463 private:
464 void OnCustomLinkClicked() override;
467 ContentSettingPluginBubbleModel::ContentSettingPluginBubbleModel(
468 Delegate* delegate,
469 WebContents* web_contents,
470 Profile* profile)
471 : ContentSettingSingleRadioGroup(delegate,
472 web_contents,
473 profile,
474 CONTENT_SETTINGS_TYPE_PLUGINS) {
475 // Disable the "Run all plugins this time" link if the setting is managed and
476 // can't be controlled by the user or if the user already clicked on the link
477 // and ran all plugins.
478 set_custom_link_enabled(!setting_is_managed() &&
479 web_contents &&
480 TabSpecificContentSettings::FromWebContents(
481 web_contents)->load_plugins_link_enabled());
482 // Build blocked plugin list.
483 if (web_contents) {
484 TabSpecificContentSettings* content_settings =
485 TabSpecificContentSettings::FromWebContents(web_contents);
487 const std::vector<base::string16>& blocked_plugins =
488 content_settings->blocked_plugin_names();
489 for (const base::string16& blocked_plugin : blocked_plugins) {
490 ListItem plugin_item(
491 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
492 IDR_BLOCKED_PLUGINS),
493 base::UTF16ToUTF8(blocked_plugin), false, 0);
494 add_list_item(plugin_item);
499 ContentSettingPluginBubbleModel::~ContentSettingPluginBubbleModel() {
500 if (settings_changed()) {
501 // If the user elected to allow all plugins then run plugins at this time.
502 if (selected_item() == kAllowButtonIndex)
503 OnCustomLinkClicked();
507 void ContentSettingPluginBubbleModel::OnCustomLinkClicked() {
508 content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble"));
509 // Web contents can be NULL if the tab was closed while the plugins
510 // settings bubble is visible.
511 if (!web_contents())
512 return;
513 #if defined(ENABLE_PLUGINS)
514 // TODO(bauerb): We should send the identifiers of blocked plugins here.
515 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
516 web_contents(), true, std::string());
517 #endif
518 set_custom_link_enabled(false);
519 TabSpecificContentSettings::FromWebContents(web_contents())->
520 set_load_plugins_link_enabled(false);
523 class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup {
524 public:
525 ContentSettingPopupBubbleModel(Delegate* delegate,
526 WebContents* web_contents,
527 Profile* profile);
528 ~ContentSettingPopupBubbleModel() override {}
530 private:
531 void OnListItemClicked(int index) override;
533 int32 item_id_from_item_index(int index) const {
534 return bubble_content().list_items[index].item_id;
538 ContentSettingPopupBubbleModel::ContentSettingPopupBubbleModel(
539 Delegate* delegate,
540 WebContents* web_contents,
541 Profile* profile)
542 : ContentSettingSingleRadioGroup(delegate,
543 web_contents,
544 profile,
545 CONTENT_SETTINGS_TYPE_POPUPS) {
546 if (web_contents) {
547 // Build blocked popup list.
548 std::map<int32, GURL> blocked_popups =
549 PopupBlockerTabHelper::FromWebContents(web_contents)
550 ->GetBlockedPopupRequests();
551 for (const std::pair<int32, GURL>& blocked_popup : blocked_popups) {
552 std::string title(blocked_popup.second.spec());
553 // The pop-up may not have a valid URL.
554 if (title.empty())
555 title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
556 ListItem popup_item(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
557 IDR_DEFAULT_FAVICON),
558 title, true, blocked_popup.first);
559 add_list_item(popup_item);
564 void ContentSettingPopupBubbleModel::OnListItemClicked(int index) {
565 if (web_contents()) {
566 PopupBlockerTabHelper::FromWebContents(web_contents())
567 ->ShowBlockedPopup(item_id_from_item_index(index));
571 // The model of the content settings bubble for media settings.
572 class ContentSettingMediaStreamBubbleModel
573 : public ContentSettingTitleAndLinkModel {
574 public:
575 ContentSettingMediaStreamBubbleModel(Delegate* delegate,
576 WebContents* web_contents,
577 Profile* profile);
579 ~ContentSettingMediaStreamBubbleModel() override;
581 void OnManageLinkClicked() override;
583 private:
584 // Helper functions to check if this bubble was invoked for microphone,
585 // camera, or both devices.
586 bool MicrophoneAccessed() const;
587 bool CameraAccessed() const;
589 void SetTitle();
590 // Sets the data for the radio buttons of the bubble.
591 void SetRadioGroup();
592 // Sets the data for the media menus of the bubble.
593 void SetMediaMenus();
594 // Set the settings management link.
595 void SetManageLink();
596 void SetCustomLink();
597 // Updates the camera and microphone setting with the passed |setting|.
598 void UpdateSettings(ContentSetting setting);
599 // Updates the camera and microphone default device with the passed |type|
600 // and device.
601 void UpdateDefaultDeviceForType(content::MediaStreamType type,
602 const std::string& device);
604 // ContentSettingBubbleModel implementation.
605 void OnRadioClicked(int radio_index) override;
606 void OnMediaMenuClicked(content::MediaStreamType type,
607 const std::string& selected_device) override;
609 // The index of the selected radio item.
610 int selected_item_;
611 // The content settings that are associated with the individual radio
612 // buttons.
613 ContentSetting radio_item_setting_[2];
614 // The state of the microphone and camera access.
615 TabSpecificContentSettings::MicrophoneCameraState state_;
618 ContentSettingMediaStreamBubbleModel::ContentSettingMediaStreamBubbleModel(
619 Delegate* delegate,
620 WebContents* web_contents,
621 Profile* profile)
622 : ContentSettingTitleAndLinkModel(
623 delegate, web_contents, profile, CONTENT_SETTINGS_TYPE_MEDIASTREAM),
624 selected_item_(0),
625 state_(TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED) {
626 // TODO(msramek): Every bubble is tied to a particular content setting.
627 // The media bubble has three states - mic only, camera only, and both.
628 // However, it is always tied to the deprecated MEDIASTREAM setting. Refactor
629 // this so that it refers to the MIC setting for microphone and CAMERA
630 // setting for camera to reduce the duplication of code in practically every
631 // method. Furthermore, it should be possible not to tie the bubble to any
632 // particular content setting type, as we still need the bubble for both
633 // camera and microphone, but should not use the deprecated MEDIASTREAM
634 // setting.
636 DCHECK(profile);
637 // Initialize the content settings associated with the individual radio
638 // buttons.
639 radio_item_setting_[0] = CONTENT_SETTING_ASK;
640 radio_item_setting_[1] = CONTENT_SETTING_BLOCK;
642 TabSpecificContentSettings* content_settings =
643 TabSpecificContentSettings::FromWebContents(web_contents);
644 state_ = content_settings->GetMicrophoneCameraState();
645 DCHECK(CameraAccessed() || MicrophoneAccessed());
647 SetTitle();
648 SetRadioGroup();
649 SetMediaMenus();
650 SetManageLink();
651 SetCustomLink();
654 ContentSettingMediaStreamBubbleModel::~ContentSettingMediaStreamBubbleModel() {
655 // On some platforms (e.g. MacOS X) it is possible to close a tab while the
656 // media stream bubble is open. This resets the web contents to NULL.
657 if (!web_contents())
658 return;
660 for (const std::pair<content::MediaStreamType, MediaMenu>& media_menu :
661 bubble_content().media_menus) {
662 if (media_menu.second.selected_device.id !=
663 media_menu.second.default_device.id) {
664 UpdateDefaultDeviceForType(media_menu.first,
665 media_menu.second.selected_device.id);
669 // Update the media settings if the radio button selection was changed.
670 if (selected_item_ != bubble_content().radio_group.default_item) {
671 UpdateSettings(radio_item_setting_[selected_item_]);
675 bool ContentSettingMediaStreamBubbleModel::MicrophoneAccessed() const {
676 return (state_ & TabSpecificContentSettings::MICROPHONE_ACCESSED) != 0;
679 bool ContentSettingMediaStreamBubbleModel::CameraAccessed() const {
680 return (state_ & TabSpecificContentSettings::CAMERA_ACCESSED) != 0;
683 void ContentSettingMediaStreamBubbleModel::OnManageLinkClicked() {
684 if (!delegate())
685 return;
687 if (MicrophoneAccessed()) {
688 delegate()->ShowContentSettingsPage(CameraAccessed()
689 ? CONTENT_SETTINGS_TYPE_MEDIASTREAM
690 : CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
691 } else {
692 delegate()->ShowContentSettingsPage(
693 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
697 void ContentSettingMediaStreamBubbleModel::SetTitle() {
698 DCHECK(CameraAccessed() || MicrophoneAccessed());
699 int title_id = 0;
700 if (state_ & TabSpecificContentSettings::MICROPHONE_BLOCKED) {
701 title_id = (state_ & TabSpecificContentSettings::CAMERA_BLOCKED) ?
702 IDS_MICROPHONE_CAMERA_BLOCKED : IDS_MICROPHONE_BLOCKED;
703 } else if (state_ & TabSpecificContentSettings::CAMERA_BLOCKED) {
704 title_id = IDS_CAMERA_BLOCKED;
705 } else if (MicrophoneAccessed()) {
706 title_id = CameraAccessed() ? IDS_MICROPHONE_CAMERA_ALLOWED
707 : IDS_MICROPHONE_ACCESSED;
708 } else if (CameraAccessed()) {
709 title_id = IDS_CAMERA_ACCESSED;
711 set_title(l10n_util::GetStringUTF8(title_id));
714 void ContentSettingMediaStreamBubbleModel::SetRadioGroup() {
715 TabSpecificContentSettings* content_settings =
716 TabSpecificContentSettings::FromWebContents(web_contents());
717 GURL url = content_settings->media_stream_access_origin();
718 RadioGroup radio_group;
719 radio_group.url = url;
721 base::string16 display_host_utf16 =
722 url_formatter::FormatUrlForSecurityDisplay(
723 url, profile()->GetPrefs()->GetString(prefs::kAcceptLanguages));
724 std::string display_host(base::UTF16ToUTF8(display_host_utf16));
725 if (display_host.empty())
726 display_host = url.spec();
728 DCHECK(CameraAccessed() || MicrophoneAccessed());
729 int radio_allow_label_id = 0;
730 int radio_block_label_id = 0;
731 if (state_ & (TabSpecificContentSettings::MICROPHONE_BLOCKED |
732 TabSpecificContentSettings::CAMERA_BLOCKED)) {
733 if (content::IsOriginSecure(url)) {
734 radio_item_setting_[0] = CONTENT_SETTING_ALLOW;
735 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ALLOW;
736 if (MicrophoneAccessed())
737 radio_allow_label_id = CameraAccessed() ?
738 IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ALLOW :
739 IDS_BLOCKED_MEDIASTREAM_MIC_ALLOW;
740 } else {
741 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ASK;
742 if (MicrophoneAccessed())
743 radio_allow_label_id = CameraAccessed() ?
744 IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ASK :
745 IDS_BLOCKED_MEDIASTREAM_MIC_ASK;
747 radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_NO_ACTION;
748 if (MicrophoneAccessed())
749 radio_block_label_id = CameraAccessed() ?
750 IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION :
751 IDS_BLOCKED_MEDIASTREAM_MIC_NO_ACTION;
752 } else {
753 if (MicrophoneAccessed() && CameraAccessed()) {
754 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION;
755 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_BLOCK;
756 } else if (MicrophoneAccessed()) {
757 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_NO_ACTION;
758 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_BLOCK;
759 } else {
760 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_NO_ACTION;
761 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_BLOCK;
764 selected_item_ =
765 (MicrophoneAccessed() && content_settings->IsContentBlocked(
766 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)) ||
767 (CameraAccessed() && content_settings->IsContentBlocked(
768 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)) ? 1 : 0;
770 std::string radio_allow_label = l10n_util::GetStringFUTF8(
771 radio_allow_label_id, base::UTF8ToUTF16(display_host));
772 std::string radio_block_label =
773 l10n_util::GetStringUTF8(radio_block_label_id);
775 radio_group.default_item = selected_item_;
776 radio_group.radio_items.push_back(radio_allow_label);
777 radio_group.radio_items.push_back(radio_block_label);
779 set_radio_group(radio_group);
780 set_radio_group_enabled(true);
783 void ContentSettingMediaStreamBubbleModel::UpdateSettings(
784 ContentSetting setting) {
785 if (profile()) {
786 HostContentSettingsMap* content_settings =
787 profile()->GetHostContentSettingsMap();
788 TabSpecificContentSettings* tab_content_settings =
789 TabSpecificContentSettings::FromWebContents(web_contents());
790 // The same patterns must be used as in other places (e.g. the infobar) in
791 // order to override the existing rule. Otherwise a new rule is created.
792 // TODO(markusheintz): Extract to a helper so that there is only a single
793 // place to touch.
794 ContentSettingsPattern primary_pattern =
795 ContentSettingsPattern::FromURLNoWildcard(
796 tab_content_settings->media_stream_access_origin());
797 ContentSettingsPattern secondary_pattern =
798 ContentSettingsPattern::Wildcard();
799 if (MicrophoneAccessed()) {
800 content_settings->SetContentSetting(
801 primary_pattern, secondary_pattern,
802 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting);
804 if (CameraAccessed()) {
805 content_settings->SetContentSetting(
806 primary_pattern, secondary_pattern,
807 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting);
812 void ContentSettingMediaStreamBubbleModel::UpdateDefaultDeviceForType(
813 content::MediaStreamType type,
814 const std::string& device) {
815 PrefService* prefs = profile()->GetPrefs();
816 if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
817 prefs->SetString(prefs::kDefaultAudioCaptureDevice, device);
818 } else {
819 DCHECK_EQ(content::MEDIA_DEVICE_VIDEO_CAPTURE, type);
820 prefs->SetString(prefs::kDefaultVideoCaptureDevice, device);
824 void ContentSettingMediaStreamBubbleModel::SetMediaMenus() {
825 TabSpecificContentSettings* content_settings =
826 TabSpecificContentSettings::FromWebContents(web_contents());
827 const std::string& requested_microphone =
828 content_settings->media_stream_requested_audio_device();
829 const std::string& requested_camera =
830 content_settings->media_stream_requested_video_device();
832 // Add microphone menu.
833 PrefService* prefs = profile()->GetPrefs();
834 MediaCaptureDevicesDispatcher* dispatcher =
835 MediaCaptureDevicesDispatcher::GetInstance();
836 const content::MediaStreamDevices& microphones =
837 dispatcher->GetAudioCaptureDevices();
839 if (MicrophoneAccessed()) {
840 MediaMenu mic_menu;
841 mic_menu.label = l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_MIC_LABEL);
842 if (!microphones.empty()) {
843 std::string preferred_mic;
844 if (requested_microphone.empty()) {
845 preferred_mic = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
846 mic_menu.disabled = false;
847 } else {
848 // Set the |disabled| to true in order to disable the device selection
849 // menu on the media settings bubble. This must be done if the website
850 // manages the microphone devices itself.
851 preferred_mic = requested_microphone;
852 mic_menu.disabled = true;
855 mic_menu.default_device = GetMediaDeviceById(preferred_mic, microphones);
856 mic_menu.selected_device = mic_menu.default_device;
858 add_media_menu(content::MEDIA_DEVICE_AUDIO_CAPTURE, mic_menu);
861 if (CameraAccessed()) {
862 const content::MediaStreamDevices& cameras =
863 dispatcher->GetVideoCaptureDevices();
864 MediaMenu camera_menu;
865 camera_menu.label =
866 l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_CAMERA_LABEL);
867 if (!cameras.empty()) {
868 std::string preferred_camera;
869 if (requested_camera.empty()) {
870 preferred_camera = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
871 camera_menu.disabled = false;
872 } else {
873 // Disable the menu since the website is managing the camera devices
874 // itself.
875 preferred_camera = requested_camera;
876 camera_menu.disabled = true;
879 camera_menu.default_device =
880 GetMediaDeviceById(preferred_camera, cameras);
881 camera_menu.selected_device = camera_menu.default_device;
883 add_media_menu(content::MEDIA_DEVICE_VIDEO_CAPTURE, camera_menu);
887 void ContentSettingMediaStreamBubbleModel::SetManageLink() {
888 // By default, the manage link refers to both media types. We only need
889 // to change the link text if only one media type was accessed.
890 if (CameraAccessed() && MicrophoneAccessed())
891 return;
893 set_manage_link(l10n_util::GetStringUTF8(MicrophoneAccessed()
894 ? IDS_MEDIASTREAM_MICROPHONE_BUBBLE_MANAGE_LINK
895 : IDS_MEDIASTREAM_CAMERA_BUBBLE_MANAGE_LINK));
898 void ContentSettingMediaStreamBubbleModel::SetCustomLink() {
899 TabSpecificContentSettings* content_settings =
900 TabSpecificContentSettings::FromWebContents(web_contents());
901 if (content_settings->IsMicrophoneCameraStateChanged()) {
902 set_custom_link(l10n_util::GetStringUTF8(
903 IDS_MEDIASTREAM_SETTING_CHANGED_MESSAGE));
907 void ContentSettingMediaStreamBubbleModel::OnRadioClicked(int radio_index) {
908 selected_item_ = radio_index;
911 void ContentSettingMediaStreamBubbleModel::OnMediaMenuClicked(
912 content::MediaStreamType type,
913 const std::string& selected_device_id) {
914 DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
915 type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
916 DCHECK_EQ(1U, bubble_content().media_menus.count(type));
917 MediaCaptureDevicesDispatcher* dispatcher =
918 MediaCaptureDevicesDispatcher::GetInstance();
919 const content::MediaStreamDevices& devices =
920 (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) ?
921 dispatcher->GetAudioCaptureDevices() :
922 dispatcher->GetVideoCaptureDevices();
923 set_selected_device(GetMediaDeviceById(selected_device_id, devices));
926 class ContentSettingDomainListBubbleModel
927 : public ContentSettingTitleAndLinkModel {
928 public:
929 ContentSettingDomainListBubbleModel(Delegate* delegate,
930 WebContents* web_contents,
931 Profile* profile,
932 ContentSettingsType content_type);
933 ~ContentSettingDomainListBubbleModel() override {}
935 private:
936 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
937 void SetDomainsAndCustomLink();
938 void OnCustomLinkClicked() override;
941 ContentSettingDomainListBubbleModel::ContentSettingDomainListBubbleModel(
942 Delegate* delegate,
943 WebContents* web_contents,
944 Profile* profile,
945 ContentSettingsType content_type)
946 : ContentSettingTitleAndLinkModel(
947 delegate, web_contents, profile, content_type) {
948 DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type) <<
949 "SetDomains currently only supports geolocation content type";
950 SetDomainsAndCustomLink();
953 void ContentSettingDomainListBubbleModel::MaybeAddDomainList(
954 const std::set<std::string>& hosts, int title_id) {
955 if (!hosts.empty()) {
956 DomainList domain_list;
957 domain_list.title = l10n_util::GetStringUTF8(title_id);
958 domain_list.hosts = hosts;
959 add_domain_list(domain_list);
963 void ContentSettingDomainListBubbleModel::SetDomainsAndCustomLink() {
964 TabSpecificContentSettings* content_settings =
965 TabSpecificContentSettings::FromWebContents(web_contents());
966 const ContentSettingsUsagesState& usages =
967 content_settings->geolocation_usages_state();
968 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state;
969 unsigned int tab_state_flags = 0;
970 usages.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
971 // Divide the tab's current geolocation users into sets according to their
972 // permission state.
973 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW],
974 IDS_GEOLOCATION_BUBBLE_SECTION_ALLOWED);
976 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK],
977 IDS_GEOLOCATION_BUBBLE_SECTION_DENIED);
979 if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) {
980 set_custom_link(l10n_util::GetStringUTF8(
981 IDS_GEOLOCATION_BUBBLE_CLEAR_LINK));
982 set_custom_link_enabled(true);
983 } else if (tab_state_flags &
984 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) {
985 set_custom_link(l10n_util::GetStringUTF8(
986 IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
990 void ContentSettingDomainListBubbleModel::OnCustomLinkClicked() {
991 if (!web_contents())
992 return;
993 // Reset this embedder's entry to default for each of the requesting
994 // origins currently on the page.
995 const GURL& embedder_url = web_contents()->GetURL();
996 TabSpecificContentSettings* content_settings =
997 TabSpecificContentSettings::FromWebContents(web_contents());
998 const ContentSettingsUsagesState::StateMap& state_map =
999 content_settings->geolocation_usages_state().state_map();
1000 HostContentSettingsMap* settings_map =
1001 profile()->GetHostContentSettingsMap();
1003 for (const std::pair<GURL, ContentSetting>& map_entry : state_map) {
1004 settings_map->SetContentSetting(
1005 ContentSettingsPattern::FromURLNoWildcard(map_entry.first),
1006 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
1007 CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
1008 CONTENT_SETTING_DEFAULT);
1012 class ContentSettingMixedScriptBubbleModel
1013 : public ContentSettingTitleLinkAndCustomModel {
1014 public:
1015 ContentSettingMixedScriptBubbleModel(Delegate* delegate,
1016 WebContents* web_contents,
1017 Profile* profile);
1019 ~ContentSettingMixedScriptBubbleModel() override {}
1021 private:
1022 void OnCustomLinkClicked() override;
1025 ContentSettingMixedScriptBubbleModel::ContentSettingMixedScriptBubbleModel(
1026 Delegate* delegate,
1027 WebContents* web_contents,
1028 Profile* profile)
1029 : ContentSettingTitleLinkAndCustomModel(delegate,
1030 web_contents,
1031 profile,
1032 CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) {
1033 content_settings::RecordMixedScriptAction(
1034 content_settings::MIXED_SCRIPT_ACTION_DISPLAYED_BUBBLE);
1035 set_custom_link_enabled(true);
1038 void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() {
1039 DCHECK(web_contents());
1040 web_contents()->SendToAllFrames(
1041 new ChromeViewMsg_SetAllowRunningInsecureContent(MSG_ROUTING_NONE, true));
1042 web_contents()->GetMainFrame()->Send(new ChromeViewMsg_ReloadFrame(
1043 web_contents()->GetMainFrame()->GetRoutingID()));
1045 content_settings::RecordMixedScriptAction(
1046 content_settings::MIXED_SCRIPT_ACTION_CLICKED_ALLOW);
1047 content_settings::RecordMixedScriptActionWithRAPPOR(
1048 content_settings::MIXED_SCRIPT_ACTION_CLICKED_ALLOW,
1049 web_contents()->GetLastCommittedURL());
1052 ContentSettingRPHBubbleModel::ContentSettingRPHBubbleModel(
1053 Delegate* delegate,
1054 WebContents* web_contents,
1055 Profile* profile,
1056 ProtocolHandlerRegistry* registry)
1057 : ContentSettingTitleAndLinkModel(delegate,
1058 web_contents,
1059 profile,
1060 CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS),
1061 selected_item_(0),
1062 registry_(registry),
1063 pending_handler_(ProtocolHandler::EmptyProtocolHandler()),
1064 previous_handler_(ProtocolHandler::EmptyProtocolHandler()) {
1065 TabSpecificContentSettings* content_settings =
1066 TabSpecificContentSettings::FromWebContents(web_contents);
1067 pending_handler_ = content_settings->pending_protocol_handler();
1068 previous_handler_ = content_settings->previous_protocol_handler();
1070 base::string16 protocol;
1071 if (pending_handler_.protocol() == "mailto") {
1072 protocol = l10n_util::GetStringUTF16(
1073 IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME);
1074 } else if (pending_handler_.protocol() == "webcal") {
1075 protocol = l10n_util::GetStringUTF16(
1076 IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME);
1077 } else {
1078 protocol = base::UTF8ToUTF16(pending_handler_.protocol());
1081 // Note that we ignore the |title| parameter.
1082 if (previous_handler_.IsEmpty()) {
1083 set_title(l10n_util::GetStringFUTF8(
1084 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM,
1085 base::UTF8ToUTF16(pending_handler_.url().host()),
1086 protocol));
1087 } else {
1088 set_title(l10n_util::GetStringFUTF8(
1089 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE,
1090 base::UTF8ToUTF16(pending_handler_.url().host()),
1091 protocol,
1092 base::UTF8ToUTF16(previous_handler_.url().host())));
1095 std::string radio_allow_label =
1096 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_ACCEPT);
1097 std::string radio_deny_label =
1098 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_DENY);
1099 std::string radio_ignore_label =
1100 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_IGNORE);
1102 GURL url = web_contents->GetURL();
1103 RadioGroup radio_group;
1104 radio_group.url = url;
1106 radio_group.radio_items.push_back(radio_allow_label);
1107 radio_group.radio_items.push_back(radio_deny_label);
1108 radio_group.radio_items.push_back(radio_ignore_label);
1109 ContentSetting setting =
1110 content_settings->pending_protocol_handler_setting();
1111 if (setting == CONTENT_SETTING_ALLOW)
1112 radio_group.default_item = RPH_ALLOW;
1113 else if (setting == CONTENT_SETTING_BLOCK)
1114 radio_group.default_item = RPH_BLOCK;
1115 else
1116 radio_group.default_item = RPH_IGNORE;
1118 selected_item_ = radio_group.default_item;
1119 set_radio_group_enabled(true);
1120 set_radio_group(radio_group);
1123 void ContentSettingRPHBubbleModel::OnRadioClicked(int radio_index) {
1124 if (selected_item_ == radio_index)
1125 return;
1127 selected_item_ = radio_index;
1129 if (radio_index == RPH_ALLOW)
1130 RegisterProtocolHandler();
1131 else if (radio_index == RPH_BLOCK)
1132 UnregisterProtocolHandler();
1133 else if (radio_index == RPH_IGNORE)
1134 IgnoreProtocolHandler();
1135 else
1136 NOTREACHED();
1139 void ContentSettingRPHBubbleModel::OnDoneClicked() {
1140 // The user has one chance to deal with the RPH content setting UI,
1141 // then we remove it.
1142 TabSpecificContentSettings::FromWebContents(web_contents())->
1143 ClearPendingProtocolHandler();
1144 content::NotificationService::current()->Notify(
1145 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
1146 content::Source<WebContents>(web_contents()),
1147 content::NotificationService::NoDetails());
1150 void ContentSettingRPHBubbleModel::RegisterProtocolHandler() {
1151 // A no-op if the handler hasn't been ignored, but needed in case the user
1152 // selects sequences like register/ignore/register.
1153 registry_->RemoveIgnoredHandler(pending_handler_);
1155 registry_->OnAcceptRegisterProtocolHandler(pending_handler_);
1156 TabSpecificContentSettings::FromWebContents(web_contents())->
1157 set_pending_protocol_handler_setting(CONTENT_SETTING_ALLOW);
1160 void ContentSettingRPHBubbleModel::UnregisterProtocolHandler() {
1161 registry_->OnDenyRegisterProtocolHandler(pending_handler_);
1162 TabSpecificContentSettings::FromWebContents(web_contents())->
1163 set_pending_protocol_handler_setting(CONTENT_SETTING_BLOCK);
1164 ClearOrSetPreviousHandler();
1167 void ContentSettingRPHBubbleModel::IgnoreProtocolHandler() {
1168 registry_->OnIgnoreRegisterProtocolHandler(pending_handler_);
1169 TabSpecificContentSettings::FromWebContents(web_contents())->
1170 set_pending_protocol_handler_setting(CONTENT_SETTING_DEFAULT);
1171 ClearOrSetPreviousHandler();
1174 void ContentSettingRPHBubbleModel::ClearOrSetPreviousHandler() {
1175 if (previous_handler_.IsEmpty()) {
1176 registry_->ClearDefault(pending_handler_.protocol());
1177 } else {
1178 registry_->OnAcceptRegisterProtocolHandler(previous_handler_);
1182 class ContentSettingMidiSysExBubbleModel
1183 : public ContentSettingTitleAndLinkModel {
1184 public:
1185 ContentSettingMidiSysExBubbleModel(Delegate* delegate,
1186 WebContents* web_contents,
1187 Profile* profile);
1188 ~ContentSettingMidiSysExBubbleModel() override {}
1190 private:
1191 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
1192 void SetDomainsAndCustomLink();
1193 void OnCustomLinkClicked() override;
1196 ContentSettingMidiSysExBubbleModel::ContentSettingMidiSysExBubbleModel(
1197 Delegate* delegate,
1198 WebContents* web_contents,
1199 Profile* profile)
1200 : ContentSettingTitleAndLinkModel(delegate,
1201 web_contents,
1202 profile,
1203 CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
1204 SetDomainsAndCustomLink();
1207 void ContentSettingMidiSysExBubbleModel::MaybeAddDomainList(
1208 const std::set<std::string>& hosts, int title_id) {
1209 if (!hosts.empty()) {
1210 DomainList domain_list;
1211 domain_list.title = l10n_util::GetStringUTF8(title_id);
1212 domain_list.hosts = hosts;
1213 add_domain_list(domain_list);
1217 void ContentSettingMidiSysExBubbleModel::SetDomainsAndCustomLink() {
1218 TabSpecificContentSettings* content_settings =
1219 TabSpecificContentSettings::FromWebContents(web_contents());
1220 const ContentSettingsUsagesState& usages_state =
1221 content_settings->midi_usages_state();
1222 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state;
1223 unsigned int tab_state_flags = 0;
1224 usages_state.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
1225 // Divide the tab's current MIDI sysex users into sets according to their
1226 // permission state.
1227 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW],
1228 IDS_MIDI_SYSEX_BUBBLE_ALLOWED);
1230 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK],
1231 IDS_MIDI_SYSEX_BUBBLE_DENIED);
1233 if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) {
1234 set_custom_link(l10n_util::GetStringUTF8(
1235 IDS_MIDI_SYSEX_BUBBLE_CLEAR_LINK));
1236 set_custom_link_enabled(true);
1237 } else if (tab_state_flags &
1238 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) {
1239 set_custom_link(l10n_util::GetStringUTF8(
1240 IDS_MIDI_SYSEX_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
1244 void ContentSettingMidiSysExBubbleModel::OnCustomLinkClicked() {
1245 if (!web_contents())
1246 return;
1247 // Reset this embedder's entry to default for each of the requesting
1248 // origins currently on the page.
1249 const GURL& embedder_url = web_contents()->GetURL();
1250 TabSpecificContentSettings* content_settings =
1251 TabSpecificContentSettings::FromWebContents(web_contents());
1252 const ContentSettingsUsagesState::StateMap& state_map =
1253 content_settings->midi_usages_state().state_map();
1254 HostContentSettingsMap* settings_map =
1255 profile()->GetHostContentSettingsMap();
1257 for (const std::pair<GURL, ContentSetting>& map_entry : state_map) {
1258 settings_map->SetContentSetting(
1259 ContentSettingsPattern::FromURLNoWildcard(map_entry.first),
1260 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
1261 CONTENT_SETTINGS_TYPE_MIDI_SYSEX, std::string(),
1262 CONTENT_SETTING_DEFAULT);
1266 // static
1267 ContentSettingBubbleModel*
1268 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
1269 Delegate* delegate,
1270 WebContents* web_contents,
1271 Profile* profile,
1272 ContentSettingsType content_type) {
1273 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
1274 return new ContentSettingCookiesBubbleModel(delegate, web_contents,
1275 profile);
1277 if (content_type == CONTENT_SETTINGS_TYPE_POPUPS) {
1278 return new ContentSettingPopupBubbleModel(delegate, web_contents, profile);
1280 if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
1281 return new ContentSettingDomainListBubbleModel(delegate, web_contents,
1282 profile, content_type);
1284 if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
1285 return new ContentSettingMediaStreamBubbleModel(delegate, web_contents,
1286 profile);
1288 if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
1289 return new ContentSettingPluginBubbleModel(delegate, web_contents, profile);
1291 if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) {
1292 return new ContentSettingMixedScriptBubbleModel(delegate, web_contents,
1293 profile);
1295 if (content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
1296 ProtocolHandlerRegistry* registry =
1297 ProtocolHandlerRegistryFactory::GetForBrowserContext(profile);
1298 return new ContentSettingRPHBubbleModel(delegate, web_contents, profile,
1299 registry);
1301 if (content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
1302 return new ContentSettingMidiSysExBubbleModel(delegate, web_contents,
1303 profile);
1305 return new ContentSettingSingleRadioGroup(delegate, web_contents, profile,
1306 content_type);
1309 ContentSettingBubbleModel::ContentSettingBubbleModel(
1310 WebContents* web_contents,
1311 Profile* profile,
1312 ContentSettingsType content_type)
1313 : web_contents_(web_contents),
1314 profile_(profile),
1315 content_type_(content_type),
1316 setting_is_managed_(false) {
1317 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
1318 content::Source<WebContents>(web_contents));
1319 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
1320 content::Source<Profile>(profile_));
1323 ContentSettingBubbleModel::~ContentSettingBubbleModel() {
1326 ContentSettingBubbleModel::RadioGroup::RadioGroup() : default_item(0) {}
1328 ContentSettingBubbleModel::RadioGroup::~RadioGroup() {}
1330 ContentSettingBubbleModel::DomainList::DomainList() {}
1332 ContentSettingBubbleModel::DomainList::~DomainList() {}
1334 ContentSettingBubbleModel::MediaMenu::MediaMenu() : disabled(false) {}
1336 ContentSettingBubbleModel::MediaMenu::~MediaMenu() {}
1338 ContentSettingBubbleModel::BubbleContent::BubbleContent()
1339 : radio_group_enabled(false),
1340 custom_link_enabled(false) {
1343 ContentSettingBubbleModel::BubbleContent::~BubbleContent() {}
1345 void ContentSettingBubbleModel::Observe(
1346 int type,
1347 const content::NotificationSource& source,
1348 const content::NotificationDetails& details) {
1349 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
1350 DCHECK_EQ(web_contents_,
1351 content::Source<WebContents>(source).ptr());
1352 web_contents_ = NULL;
1353 } else {
1354 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
1355 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
1356 profile_ = NULL;