1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" 6 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/content_settings_utils.h" 12 #include "chrome/browser/content_settings/cookie_settings.h" 13 #include "chrome/browser/custom_handlers/protocol_handler_registry.h" 14 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" 15 #include "chrome/browser/favicon/favicon_tab_helper.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/browser/ui/content_settings/media_setting_changed_infobar_delegate.h" 25 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/pref_names.h" 27 #include "chrome/common/render_messages.h" 28 #include "chrome/grit/generated_resources.h" 29 #include "components/content_settings/core/common/content_settings.h" 30 #include "content/public/browser/notification_service.h" 31 #include "content/public/browser/render_frame_host.h" 32 #include "content/public/browser/render_process_host.h" 33 #include "content/public/browser/render_view_host.h" 34 #include "content/public/browser/user_metrics.h" 35 #include "content/public/browser/web_contents.h" 36 #include "content/public/browser/web_contents_delegate.h" 37 #include "grit/components_strings.h" 38 #include "net/base/net_util.h" 39 #include "ui/base/l10n/l10n_util.h" 40 #include "ui/base/resource/resource_bundle.h" 41 #include "ui/resources/grit/ui_resources.h" 42 43 using base::UserMetricsAction; 44 using content::WebContents; 45 using content_settings::SettingInfo; 46 using content_settings::SettingSource; 47 using content_settings::SETTING_SOURCE_USER; 48 using content_settings::SETTING_SOURCE_NONE; 49 50 namespace { 51 52 const int kAllowButtonIndex = 0; 53 54 struct ContentSettingsTypeIdEntry { 55 ContentSettingsType type; 56 int id; 57 }; 58 59 int GetIdForContentType(const ContentSettingsTypeIdEntry* entries, 60 size_t num_entries, 61 ContentSettingsType type) { 62 for (size_t i = 0; i < num_entries; ++i) { 63 if (entries[i].type == type) 64 return entries[i].id; 65 } 66 return 0; 67 } 68 69 const content::MediaStreamDevice& GetMediaDeviceById( 70 const std::string& device_id, 71 const content::MediaStreamDevices& devices) { 72 DCHECK(!devices.empty()); 73 for (content::MediaStreamDevices::const_iterator it = devices.begin(); 74 it != devices.end(); ++it) { 75 if (it->id == device_id) 76 return *(it); 77 } 78 79 // A device with the |device_id| was not found. It is likely that the device 80 // has been unplugged from the OS. Return the first device as the default 81 // device. 82 return *devices.begin(); 83 } 84 85 } // namespace 86 87 ContentSettingTitleAndLinkModel::ContentSettingTitleAndLinkModel( 88 Delegate* delegate, 89 WebContents* web_contents, 90 Profile* profile, 91 ContentSettingsType content_type) 92 : ContentSettingBubbleModel(web_contents, profile, content_type), 93 delegate_(delegate) { 94 // Notifications do not have a bubble. 95 DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); 96 SetTitle(); 97 SetManageLink(); 98 SetLearnMoreLink(); 99 } 100 101 void ContentSettingTitleAndLinkModel::SetTitle() { 102 static const ContentSettingsTypeIdEntry kBlockedTitleIDs[] = { 103 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE}, 104 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE}, 105 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE}, 106 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_MESSAGE}, 107 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TITLE}, 108 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, 109 IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT}, 110 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, 111 IDS_BLOCKED_PPAPI_BROKER_TITLE}, 112 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_TITLE}, 113 }; 114 // Fields as for kBlockedTitleIDs, above. 115 static const ContentSettingsTypeIdEntry kAccessedTitleIDs[] = { 116 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_TITLE}, 117 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_TITLE}, 118 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_TITLE}, 119 }; 120 const ContentSettingsTypeIdEntry *title_ids = kBlockedTitleIDs; 121 size_t num_title_ids = arraysize(kBlockedTitleIDs); 122 if (web_contents() && 123 TabSpecificContentSettings::FromWebContents( 124 web_contents())->IsContentAllowed(content_type()) && 125 !TabSpecificContentSettings::FromWebContents( 126 web_contents())->IsContentBlocked(content_type())) { 127 title_ids = kAccessedTitleIDs; 128 num_title_ids = arraysize(kAccessedTitleIDs); 129 } 130 int title_id = 131 GetIdForContentType(title_ids, num_title_ids, content_type()); 132 if (title_id) 133 set_title(l10n_util::GetStringUTF8(title_id)); 134 } 135 136 void ContentSettingTitleAndLinkModel::SetManageLink() { 137 static const ContentSettingsTypeIdEntry kLinkIDs[] = { 138 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_LINK}, 139 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_LINK}, 140 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_LINK}, 141 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LINK}, 142 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_LINK}, 143 {CONTENT_SETTINGS_TYPE_GEOLOCATION, IDS_GEOLOCATION_BUBBLE_MANAGE_LINK}, 144 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_LEARN_MORE}, 145 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, IDS_HANDLERS_BUBBLE_MANAGE_LINK}, 146 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, IDS_MEDIASTREAM_BUBBLE_MANAGE_LINK}, 147 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_PPAPI_BROKER_BUBBLE_MANAGE_LINK}, 148 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOADS_LINK}, 149 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, IDS_MIDI_SYSEX_BUBBLE_MANAGE_LINK}, 150 }; 151 set_manage_link(l10n_util::GetStringUTF8( 152 GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type()))); 153 } 154 155 void ContentSettingTitleAndLinkModel::OnManageLinkClicked() { 156 if (delegate_) 157 delegate_->ShowContentSettingsPage(content_type()); 158 } 159 160 void ContentSettingTitleAndLinkModel::SetLearnMoreLink() { 161 static const ContentSettingsTypeIdEntry kLearnMoreIDs[] = { 162 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_LEARN_MORE}, 163 }; 164 int learn_more_id = 165 GetIdForContentType(kLearnMoreIDs, arraysize(kLearnMoreIDs), 166 content_type()); 167 if (learn_more_id) 168 set_learn_more_link(l10n_util::GetStringUTF8(learn_more_id)); 169 } 170 171 void ContentSettingTitleAndLinkModel::OnLearnMoreLinkClicked() { 172 if (delegate_) 173 delegate_->ShowLearnMorePage(content_type()); 174 } 175 176 class ContentSettingTitleLinkAndCustomModel 177 : public ContentSettingTitleAndLinkModel { 178 public: 179 ContentSettingTitleLinkAndCustomModel(Delegate* delegate, 180 WebContents* web_contents, 181 Profile* profile, 182 ContentSettingsType content_type); 183 virtual ~ContentSettingTitleLinkAndCustomModel() {} 184 185 private: 186 void SetCustomLink(); 187 virtual void OnCustomLinkClicked() OVERRIDE {} 188 }; 189 190 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel( 191 Delegate* delegate, 192 WebContents* web_contents, 193 Profile* profile, 194 ContentSettingsType content_type) 195 : ContentSettingTitleAndLinkModel( 196 delegate, web_contents, profile, content_type) { 197 SetCustomLink(); 198 } 199 200 void ContentSettingTitleLinkAndCustomModel::SetCustomLink() { 201 static const ContentSettingsTypeIdEntry kCustomIDs[] = { 202 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO}, 203 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL}, 204 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_ALLOW_INSECURE_CONTENT_BUTTON}, 205 }; 206 int custom_link_id = 207 GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type()); 208 if (custom_link_id) 209 set_custom_link(l10n_util::GetStringUTF8(custom_link_id)); 210 } 211 212 class ContentSettingSingleRadioGroup 213 : public ContentSettingTitleLinkAndCustomModel { 214 public: 215 ContentSettingSingleRadioGroup(Delegate* delegate, 216 WebContents* web_contents, 217 Profile* profile, 218 ContentSettingsType content_type); 219 virtual ~ContentSettingSingleRadioGroup(); 220 221 protected: 222 bool settings_changed() const; 223 int selected_item() const { return selected_item_; } 224 225 private: 226 void SetRadioGroup(); 227 void AddException(ContentSetting setting); 228 virtual void OnRadioClicked(int radio_index) OVERRIDE; 229 230 ContentSetting block_setting_; 231 int selected_item_; 232 }; 233 234 ContentSettingSingleRadioGroup::ContentSettingSingleRadioGroup( 235 Delegate* delegate, 236 WebContents* web_contents, 237 Profile* profile, 238 ContentSettingsType content_type) 239 : ContentSettingTitleLinkAndCustomModel(delegate, web_contents, profile, 240 content_type), 241 block_setting_(CONTENT_SETTING_BLOCK), 242 selected_item_(0) { 243 SetRadioGroup(); 244 } 245 246 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() { 247 if (settings_changed()) { 248 ContentSetting setting = 249 selected_item_ == kAllowButtonIndex ? 250 CONTENT_SETTING_ALLOW : 251 block_setting_; 252 AddException(setting); 253 } 254 } 255 256 bool ContentSettingSingleRadioGroup::settings_changed() const { 257 return selected_item_ != bubble_content().radio_group.default_item; 258 } 259 260 // Initialize the radio group by setting the appropriate labels for the 261 // content type and setting the default value based on the content setting. 262 void ContentSettingSingleRadioGroup::SetRadioGroup() { 263 GURL url = web_contents()->GetURL(); 264 base::string16 display_host; 265 net::AppendFormattedHost( 266 url, 267 profile()->GetPrefs()->GetString(prefs::kAcceptLanguages), 268 &display_host); 269 270 if (display_host.empty()) 271 display_host = base::ASCIIToUTF16(url.spec()); 272 273 TabSpecificContentSettings* content_settings = 274 TabSpecificContentSettings::FromWebContents(web_contents()); 275 bool allowed = 276 !content_settings->IsContentBlocked(content_type()); 277 DCHECK(!allowed || 278 content_settings->IsContentAllowed(content_type())); 279 280 RadioGroup radio_group; 281 radio_group.url = url; 282 283 static const ContentSettingsTypeIdEntry kBlockedAllowIDs[] = { 284 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK}, 285 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_UNBLOCK}, 286 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_UNBLOCK}, 287 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_UNBLOCK_ALL}, 288 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_UNBLOCK}, 289 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_UNBLOCK}, 290 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_UNBLOCK}, 291 }; 292 // Fields as for kBlockedAllowIDs, above. 293 static const ContentSettingsTypeIdEntry kAllowedAllowIDs[] = { 294 // TODO(bauerb): The string shouldn't be "unblock" (they weren't blocked). 295 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK}, 296 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_NO_ACTION}, 297 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_NO_ACTION}, 298 }; 299 300 std::string radio_allow_label; 301 if (allowed) { 302 int resource_id = GetIdForContentType(kAllowedAllowIDs, 303 arraysize(kAllowedAllowIDs), 304 content_type()); 305 radio_allow_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ? 306 l10n_util::GetStringFUTF8(resource_id, display_host) : 307 l10n_util::GetStringUTF8(resource_id); 308 } else { 309 radio_allow_label = l10n_util::GetStringFUTF8( 310 GetIdForContentType(kBlockedAllowIDs, arraysize(kBlockedAllowIDs), 311 content_type()), 312 display_host); 313 } 314 315 static const ContentSettingsTypeIdEntry kBlockedBlockIDs[] = { 316 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION}, 317 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_NO_ACTION}, 318 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_NO_ACTION}, 319 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_NO_ACTION}, 320 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_NO_ACTION}, 321 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_NO_ACTION}, 322 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_NO_ACTION}, 323 }; 324 static const ContentSettingsTypeIdEntry kAllowedBlockIDs[] = { 325 // TODO(bauerb): The string should say "block". 326 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION}, 327 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_BLOCK}, 328 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_BLOCK}, 329 }; 330 331 std::string radio_block_label; 332 if (allowed) { 333 int resource_id = GetIdForContentType(kAllowedBlockIDs, 334 arraysize(kAllowedBlockIDs), 335 content_type()); 336 radio_block_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ? 337 l10n_util::GetStringUTF8(resource_id) : 338 l10n_util::GetStringFUTF8(resource_id, display_host); 339 } else { 340 radio_block_label = l10n_util::GetStringUTF8( 341 GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs), 342 content_type())); 343 } 344 345 radio_group.radio_items.push_back(radio_allow_label); 346 radio_group.radio_items.push_back(radio_block_label); 347 ContentSetting setting; 348 SettingSource setting_source = SETTING_SOURCE_NONE; 349 bool setting_is_wildcard = false; 350 351 if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) { 352 CookieSettings* cookie_settings = 353 CookieSettings::Factory::GetForProfile(profile()).get(); 354 setting = cookie_settings->GetCookieSetting( 355 url, url, true, &setting_source); 356 } else { 357 SettingInfo info; 358 HostContentSettingsMap* map = profile()->GetHostContentSettingsMap(); 359 scoped_ptr<base::Value> value = 360 map->GetWebsiteSetting(url, url, content_type(), std::string(), &info); 361 setting = content_settings::ValueToContentSetting(value.get()); 362 setting_source = info.source; 363 setting_is_wildcard = 364 info.primary_pattern == ContentSettingsPattern::Wildcard() && 365 info.secondary_pattern == ContentSettingsPattern::Wildcard(); 366 } 367 368 if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS && 369 setting == CONTENT_SETTING_ALLOW && 370 setting_is_wildcard) { 371 // In the corner case of unrecognized plugins (which are now blocked by 372 // default) we indicate the blocked state in the UI and allow the user to 373 // whitelist. 374 radio_group.default_item = 1; 375 } else if (setting == CONTENT_SETTING_ALLOW) { 376 radio_group.default_item = kAllowButtonIndex; 377 // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|. 378 } else { 379 radio_group.default_item = 1; 380 block_setting_ = setting; 381 } 382 383 set_setting_is_managed(setting_source != SETTING_SOURCE_USER); 384 if (setting_source != SETTING_SOURCE_USER) { 385 set_radio_group_enabled(false); 386 } else { 387 set_radio_group_enabled(true); 388 } 389 selected_item_ = radio_group.default_item; 390 set_radio_group(radio_group); 391 } 392 393 void ContentSettingSingleRadioGroup::AddException(ContentSetting setting) { 394 if (profile()) { 395 profile()->GetHostContentSettingsMap()->AddExceptionForURL( 396 bubble_content().radio_group.url, 397 bubble_content().radio_group.url, 398 content_type(), 399 setting); 400 } 401 } 402 403 void ContentSettingSingleRadioGroup::OnRadioClicked(int radio_index) { 404 selected_item_ = radio_index; 405 } 406 407 class ContentSettingCookiesBubbleModel : public ContentSettingSingleRadioGroup { 408 public: 409 ContentSettingCookiesBubbleModel(Delegate* delegate, 410 WebContents* web_contents, 411 Profile* profile, 412 ContentSettingsType content_type); 413 414 virtual ~ContentSettingCookiesBubbleModel(); 415 416 private: 417 virtual void OnCustomLinkClicked() OVERRIDE; 418 }; 419 420 ContentSettingCookiesBubbleModel::ContentSettingCookiesBubbleModel( 421 Delegate* delegate, 422 WebContents* web_contents, 423 Profile* profile, 424 ContentSettingsType content_type) 425 : ContentSettingSingleRadioGroup( 426 delegate, web_contents, profile, content_type) { 427 DCHECK_EQ(CONTENT_SETTINGS_TYPE_COOKIES, content_type); 428 set_custom_link_enabled(true); 429 } 430 431 ContentSettingCookiesBubbleModel::~ContentSettingCookiesBubbleModel() { 432 // On some plattforms e.g. MacOS X it is possible to close a tab while the 433 // cookies settings bubble is open. This resets the web contents to NULL. 434 if (settings_changed() && web_contents()) { 435 CollectedCookiesInfoBarDelegate::Create( 436 InfoBarService::FromWebContents(web_contents())); 437 } 438 } 439 440 void ContentSettingCookiesBubbleModel::OnCustomLinkClicked() { 441 if (!web_contents()) 442 return; 443 content::NotificationService::current()->Notify( 444 chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN, 445 content::Source<TabSpecificContentSettings>( 446 TabSpecificContentSettings::FromWebContents(web_contents())), 447 content::NotificationService::NoDetails()); 448 delegate()->ShowCollectedCookiesDialog(web_contents()); 449 } 450 451 class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup { 452 public: 453 ContentSettingPluginBubbleModel(Delegate* delegate, 454 WebContents* web_contents, 455 Profile* profile, 456 ContentSettingsType content_type); 457 458 virtual ~ContentSettingPluginBubbleModel(); 459 460 private: 461 virtual void OnCustomLinkClicked() OVERRIDE; 462 }; 463 464 ContentSettingPluginBubbleModel::ContentSettingPluginBubbleModel( 465 Delegate* delegate, 466 WebContents* web_contents, 467 Profile* profile, 468 ContentSettingsType content_type) 469 : ContentSettingSingleRadioGroup( 470 delegate, web_contents, profile, content_type) { 471 DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS); 472 // Disable the "Run all plugins this time" link if the setting is managed and 473 // can't be controlled by the user or if the user already clicked on the link 474 // and ran all plugins. 475 set_custom_link_enabled(!setting_is_managed() && 476 web_contents && 477 TabSpecificContentSettings::FromWebContents( 478 web_contents)->load_plugins_link_enabled()); 479 } 480 481 ContentSettingPluginBubbleModel::~ContentSettingPluginBubbleModel() { 482 if (settings_changed()) { 483 // If the user elected to allow all plugins then run plugins at this time. 484 if (selected_item() == kAllowButtonIndex) 485 OnCustomLinkClicked(); 486 } 487 } 488 489 void ContentSettingPluginBubbleModel::OnCustomLinkClicked() { 490 content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble")); 491 DCHECK(web_contents()); 492 #if defined(ENABLE_PLUGINS) 493 // TODO(bauerb): We should send the identifiers of blocked plug-ins here. 494 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins( 495 web_contents(), true, std::string()); 496 #endif 497 set_custom_link_enabled(false); 498 TabSpecificContentSettings::FromWebContents(web_contents())-> 499 set_load_plugins_link_enabled(false); 500 } 501 502 class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup { 503 public: 504 ContentSettingPopupBubbleModel(Delegate* delegate, 505 WebContents* web_contents, 506 Profile* profile, 507 ContentSettingsType content_type); 508 virtual ~ContentSettingPopupBubbleModel() {} 509 510 private: 511 void SetPopups(); 512 virtual void OnPopupClicked(int index) OVERRIDE; 513 }; 514 515 ContentSettingPopupBubbleModel::ContentSettingPopupBubbleModel( 516 Delegate* delegate, 517 WebContents* web_contents, 518 Profile* profile, 519 ContentSettingsType content_type) 520 : ContentSettingSingleRadioGroup( 521 delegate, web_contents, profile, content_type) { 522 SetPopups(); 523 } 524 525 526 void ContentSettingPopupBubbleModel::SetPopups() { 527 std::map<int32, GURL> blocked_popups = 528 PopupBlockerTabHelper::FromWebContents(web_contents()) 529 ->GetBlockedPopupRequests(); 530 for (std::map<int32, GURL>::const_iterator iter = blocked_popups.begin(); 531 iter != blocked_popups.end(); 532 ++iter) { 533 std::string title(iter->second.spec()); 534 // The popup may not have a valid URL. 535 if (title.empty()) 536 title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE); 537 PopupItem popup_item( 538 ui::ResourceBundle::GetSharedInstance().GetImageNamed( 539 IDR_DEFAULT_FAVICON), 540 title, 541 iter->first); 542 add_popup(popup_item); 543 } 544 } 545 546 void ContentSettingPopupBubbleModel::OnPopupClicked(int index) { 547 if (web_contents()) { 548 PopupBlockerTabHelper::FromWebContents(web_contents())-> 549 ShowBlockedPopup(bubble_content().popup_items[index].popup_id); 550 } 551 } 552 553 // The model of the content settings bubble for media settings. 554 class ContentSettingMediaStreamBubbleModel 555 : public ContentSettingTitleAndLinkModel { 556 public: 557 ContentSettingMediaStreamBubbleModel(Delegate* delegate, 558 WebContents* web_contents, 559 Profile* profile); 560 561 virtual ~ContentSettingMediaStreamBubbleModel(); 562 563 private: 564 void SetTitle(); 565 // Sets the data for the radio buttons of the bubble. 566 void SetRadioGroup(); 567 // Sets the data for the media menus of the bubble. 568 void SetMediaMenus(); 569 // Updates the camera and microphone setting with the passed |setting|. 570 void UpdateSettings(ContentSetting setting); 571 // Updates the camera and microphone default device with the passed |type| 572 // and device. 573 void UpdateDefaultDeviceForType(content::MediaStreamType type, 574 const std::string& device); 575 576 // ContentSettingBubbleModel implementation. 577 virtual void OnRadioClicked(int radio_index) OVERRIDE; 578 virtual void OnMediaMenuClicked(content::MediaStreamType type, 579 const std::string& selected_device) OVERRIDE; 580 581 // The index of the selected radio item. 582 int selected_item_; 583 // The content settings that are associated with the individual radio 584 // buttons. 585 ContentSetting radio_item_setting_[2]; 586 // The state of the microphone and camera access. 587 TabSpecificContentSettings::MicrophoneCameraState state_; 588 }; 589 590 ContentSettingMediaStreamBubbleModel::ContentSettingMediaStreamBubbleModel( 591 Delegate* delegate, 592 WebContents* web_contents, 593 Profile* profile) 594 : ContentSettingTitleAndLinkModel( 595 delegate, web_contents, profile, CONTENT_SETTINGS_TYPE_MEDIASTREAM), 596 selected_item_(0), 597 state_(TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED) { 598 DCHECK(profile); 599 // Initialize the content settings associated with the individual radio 600 // buttons. 601 radio_item_setting_[0] = CONTENT_SETTING_ASK; 602 radio_item_setting_[1] = CONTENT_SETTING_BLOCK; 603 604 TabSpecificContentSettings* content_settings = 605 TabSpecificContentSettings::FromWebContents(web_contents); 606 state_ = content_settings->GetMicrophoneCameraState(); 607 608 SetTitle(); 609 SetRadioGroup(); 610 SetMediaMenus(); 611 } 612 613 ContentSettingMediaStreamBubbleModel::~ContentSettingMediaStreamBubbleModel() { 614 // On some platforms (e.g. MacOS X) it is possible to close a tab while the 615 // media stream bubble is open. This resets the web contents to NULL. 616 if (!web_contents()) 617 return; 618 619 bool media_setting_changed = false; 620 for (MediaMenuMap::const_iterator it = bubble_content().media_menus.begin(); 621 it != bubble_content().media_menus.end(); ++it) { 622 if (it->second.selected_device.id != it->second.default_device.id) { 623 UpdateDefaultDeviceForType(it->first, it->second.selected_device.id); 624 media_setting_changed = true; 625 } 626 } 627 628 // Update the media settings if the radio button selection was changed. 629 if (selected_item_ != bubble_content().radio_group.default_item) { 630 UpdateSettings(radio_item_setting_[selected_item_]); 631 media_setting_changed = true; 632 } 633 634 // Trigger the reload infobar if the media setting has been changed. 635 if (media_setting_changed) { 636 MediaSettingChangedInfoBarDelegate::Create( 637 InfoBarService::FromWebContents(web_contents())); 638 } 639 } 640 641 void ContentSettingMediaStreamBubbleModel::SetTitle() { 642 int title_id = 0; 643 switch (state_) { 644 case TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED: 645 // If neither microphone nor camera stream was accessed, then there is no 646 // icon didplayed in the omnibox and no settings bubble availbale. Hence 647 // there is no title. 648 NOTREACHED(); 649 return; 650 case TabSpecificContentSettings::MICROPHONE_ACCESSED: 651 title_id = IDS_MICROPHONE_ACCESSED; 652 break; 653 case TabSpecificContentSettings::CAMERA_ACCESSED: 654 title_id = IDS_CAMERA_ACCESSED; 655 break; 656 case TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED: 657 title_id = IDS_MICROPHONE_CAMERA_ALLOWED; 658 break; 659 case TabSpecificContentSettings::MICROPHONE_BLOCKED: 660 title_id = IDS_MICROPHONE_BLOCKED; 661 break; 662 case TabSpecificContentSettings::CAMERA_BLOCKED: 663 title_id = IDS_CAMERA_BLOCKED; 664 break; 665 case TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED: 666 title_id = IDS_MICROPHONE_CAMERA_BLOCKED; 667 break; 668 } 669 set_title(l10n_util::GetStringUTF8(title_id)); 670 } 671 672 void ContentSettingMediaStreamBubbleModel::SetRadioGroup() { 673 TabSpecificContentSettings* content_settings = 674 TabSpecificContentSettings::FromWebContents(web_contents()); 675 GURL url = content_settings->media_stream_access_origin(); 676 RadioGroup radio_group; 677 radio_group.url = url; 678 679 base::string16 display_host_utf16; 680 net::AppendFormattedHost( 681 url, 682 profile()->GetPrefs()->GetString(prefs::kAcceptLanguages), 683 &display_host_utf16); 684 std::string display_host(base::UTF16ToUTF8(display_host_utf16)); 685 if (display_host.empty()) 686 display_host = url.spec(); 687 688 int radio_allow_label_id = 0; 689 int radio_block_label_id = 0; 690 switch (state_) { 691 case TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED: 692 NOTREACHED(); 693 return; 694 case TabSpecificContentSettings::MICROPHONE_ACCESSED: 695 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_NO_ACTION; 696 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_BLOCK; 697 selected_item_ = 0; 698 break; 699 case TabSpecificContentSettings::CAMERA_ACCESSED: 700 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_NO_ACTION; 701 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_BLOCK; 702 selected_item_ = 0; 703 break; 704 case TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED: 705 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION; 706 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_BLOCK; 707 selected_item_ = 0; 708 break; 709 case TabSpecificContentSettings::MICROPHONE_BLOCKED: 710 if (url.SchemeIsSecure()) { 711 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_ALLOW; 712 radio_item_setting_[0] = CONTENT_SETTING_ALLOW; 713 } else { 714 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_ASK; 715 } 716 717 radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_NO_ACTION; 718 selected_item_ = 1; 719 break; 720 case TabSpecificContentSettings::CAMERA_BLOCKED: 721 if (url.SchemeIsSecure()) { 722 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ALLOW; 723 radio_item_setting_[0] = CONTENT_SETTING_ALLOW; 724 } else { 725 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ASK; 726 } 727 728 radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_NO_ACTION; 729 selected_item_ = 1; 730 break; 731 case TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED: 732 if (url.SchemeIsSecure()) { 733 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ALLOW; 734 radio_item_setting_[0] = CONTENT_SETTING_ALLOW; 735 } else { 736 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ASK; 737 } 738 739 radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION; 740 selected_item_ = 1; 741 break; 742 } 743 744 std::string radio_allow_label = l10n_util::GetStringFUTF8( 745 radio_allow_label_id, base::UTF8ToUTF16(display_host)); 746 std::string radio_block_label = 747 l10n_util::GetStringUTF8(radio_block_label_id); 748 749 radio_group.default_item = selected_item_; 750 radio_group.radio_items.push_back(radio_allow_label); 751 radio_group.radio_items.push_back(radio_block_label); 752 753 set_radio_group(radio_group); 754 set_radio_group_enabled(true); 755 } 756 757 void ContentSettingMediaStreamBubbleModel::UpdateSettings( 758 ContentSetting setting) { 759 if (profile()) { 760 HostContentSettingsMap* content_settings = 761 profile()->GetHostContentSettingsMap(); 762 TabSpecificContentSettings* tab_content_settings = 763 TabSpecificContentSettings::FromWebContents(web_contents()); 764 // The same patterns must be used as in other places (e.g. the infobar) in 765 // order to override the existing rule. Otherwise a new rule is created. 766 // TODO(markusheintz): Extract to a helper so that there is only a single 767 // place to touch. 768 ContentSettingsPattern primary_pattern = 769 ContentSettingsPattern::FromURLNoWildcard( 770 tab_content_settings->media_stream_access_origin()); 771 ContentSettingsPattern secondary_pattern = 772 ContentSettingsPattern::Wildcard(); 773 if (state_ == TabSpecificContentSettings::MICROPHONE_ACCESSED || 774 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED || 775 state_ == TabSpecificContentSettings::MICROPHONE_BLOCKED || 776 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED) { 777 content_settings->SetContentSetting( 778 primary_pattern, secondary_pattern, 779 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting); 780 } 781 if (state_ == TabSpecificContentSettings::CAMERA_ACCESSED || 782 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED || 783 state_ == TabSpecificContentSettings::CAMERA_BLOCKED || 784 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED) { 785 content_settings->SetContentSetting( 786 primary_pattern, secondary_pattern, 787 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting); 788 } 789 } 790 } 791 792 void ContentSettingMediaStreamBubbleModel::UpdateDefaultDeviceForType( 793 content::MediaStreamType type, 794 const std::string& device) { 795 PrefService* prefs = profile()->GetPrefs(); 796 if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { 797 prefs->SetString(prefs::kDefaultAudioCaptureDevice, device); 798 } else { 799 DCHECK_EQ(content::MEDIA_DEVICE_VIDEO_CAPTURE, type); 800 prefs->SetString(prefs::kDefaultVideoCaptureDevice, device); 801 } 802 } 803 804 void ContentSettingMediaStreamBubbleModel::SetMediaMenus() { 805 TabSpecificContentSettings* content_settings = 806 TabSpecificContentSettings::FromWebContents(web_contents()); 807 const std::string& requested_microphone = 808 content_settings->media_stream_requested_audio_device(); 809 const std::string& requested_camera = 810 content_settings->media_stream_requested_video_device(); 811 812 // Add microphone menu. 813 PrefService* prefs = profile()->GetPrefs(); 814 MediaCaptureDevicesDispatcher* dispatcher = 815 MediaCaptureDevicesDispatcher::GetInstance(); 816 const content::MediaStreamDevices& microphones = 817 dispatcher->GetAudioCaptureDevices(); 818 819 bool show_mic_menu = 820 (state_ == TabSpecificContentSettings::MICROPHONE_ACCESSED || 821 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED || 822 state_ == TabSpecificContentSettings::MICROPHONE_BLOCKED || 823 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED); 824 bool show_camera_menu = 825 (state_ == TabSpecificContentSettings::CAMERA_ACCESSED || 826 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED || 827 state_ == TabSpecificContentSettings::CAMERA_BLOCKED || 828 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED); 829 DCHECK(show_mic_menu || show_camera_menu); 830 831 if (show_mic_menu) { 832 MediaMenu mic_menu; 833 mic_menu.label = l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_MIC_LABEL); 834 if (!microphones.empty()) { 835 std::string preferred_mic; 836 if (requested_microphone.empty()) { 837 preferred_mic = prefs->GetString(prefs::kDefaultAudioCaptureDevice); 838 mic_menu.disabled = false; 839 } else { 840 // Set the |disabled| to true in order to disable the device selection 841 // menu on the media settings bubble. This must be done if the website 842 // manages the microphone devices itself. 843 preferred_mic = requested_microphone; 844 mic_menu.disabled = true; 845 } 846 847 mic_menu.default_device = GetMediaDeviceById(preferred_mic, microphones); 848 mic_menu.selected_device = mic_menu.default_device; 849 } 850 add_media_menu(content::MEDIA_DEVICE_AUDIO_CAPTURE, mic_menu); 851 } 852 853 if (show_camera_menu) { 854 const content::MediaStreamDevices& cameras = 855 dispatcher->GetVideoCaptureDevices(); 856 MediaMenu camera_menu; 857 camera_menu.label = 858 l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_CAMERA_LABEL); 859 if (!cameras.empty()) { 860 std::string preferred_camera; 861 if (requested_camera.empty()) { 862 preferred_camera = prefs->GetString(prefs::kDefaultVideoCaptureDevice); 863 camera_menu.disabled = false; 864 } else { 865 // Disable the menu since the website is managing the camera devices 866 // itself. 867 preferred_camera = requested_camera; 868 camera_menu.disabled = true; 869 } 870 871 camera_menu.default_device = 872 GetMediaDeviceById(preferred_camera, cameras); 873 camera_menu.selected_device = camera_menu.default_device; 874 } 875 add_media_menu(content::MEDIA_DEVICE_VIDEO_CAPTURE, camera_menu); 876 } 877 } 878 879 void ContentSettingMediaStreamBubbleModel::OnRadioClicked(int radio_index) { 880 selected_item_ = radio_index; 881 } 882 883 void ContentSettingMediaStreamBubbleModel::OnMediaMenuClicked( 884 content::MediaStreamType type, 885 const std::string& selected_device_id) { 886 DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE || 887 type == content::MEDIA_DEVICE_VIDEO_CAPTURE); 888 DCHECK_EQ(1U, bubble_content().media_menus.count(type)); 889 MediaCaptureDevicesDispatcher* dispatcher = 890 MediaCaptureDevicesDispatcher::GetInstance(); 891 const content::MediaStreamDevices& devices = 892 (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) ? 893 dispatcher->GetAudioCaptureDevices() : 894 dispatcher->GetVideoCaptureDevices(); 895 set_selected_device(GetMediaDeviceById(selected_device_id, devices)); 896 } 897 898 class ContentSettingDomainListBubbleModel 899 : public ContentSettingTitleAndLinkModel { 900 public: 901 ContentSettingDomainListBubbleModel(Delegate* delegate, 902 WebContents* web_contents, 903 Profile* profile, 904 ContentSettingsType content_type); 905 virtual ~ContentSettingDomainListBubbleModel() {} 906 907 private: 908 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id); 909 void SetDomainsAndCustomLink(); 910 virtual void OnCustomLinkClicked() OVERRIDE; 911 }; 912 913 ContentSettingDomainListBubbleModel::ContentSettingDomainListBubbleModel( 914 Delegate* delegate, 915 WebContents* web_contents, 916 Profile* profile, 917 ContentSettingsType content_type) 918 : ContentSettingTitleAndLinkModel( 919 delegate, web_contents, profile, content_type) { 920 DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type) << 921 "SetDomains currently only supports geolocation content type"; 922 SetDomainsAndCustomLink(); 923 } 924 925 void ContentSettingDomainListBubbleModel::MaybeAddDomainList( 926 const std::set<std::string>& hosts, int title_id) { 927 if (!hosts.empty()) { 928 DomainList domain_list; 929 domain_list.title = l10n_util::GetStringUTF8(title_id); 930 domain_list.hosts = hosts; 931 add_domain_list(domain_list); 932 } 933 } 934 935 void ContentSettingDomainListBubbleModel::SetDomainsAndCustomLink() { 936 TabSpecificContentSettings* content_settings = 937 TabSpecificContentSettings::FromWebContents(web_contents()); 938 const ContentSettingsUsagesState& usages = 939 content_settings->geolocation_usages_state(); 940 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state; 941 unsigned int tab_state_flags = 0; 942 usages.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags); 943 // Divide the tab's current geolocation users into sets according to their 944 // permission state. 945 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW], 946 IDS_GEOLOCATION_BUBBLE_SECTION_ALLOWED); 947 948 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK], 949 IDS_GEOLOCATION_BUBBLE_SECTION_DENIED); 950 951 if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) { 952 set_custom_link(l10n_util::GetStringUTF8( 953 IDS_GEOLOCATION_BUBBLE_CLEAR_LINK)); 954 set_custom_link_enabled(true); 955 } else if (tab_state_flags & 956 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) { 957 set_custom_link(l10n_util::GetStringUTF8( 958 IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR)); 959 } 960 } 961 962 void ContentSettingDomainListBubbleModel::OnCustomLinkClicked() { 963 if (!web_contents()) 964 return; 965 // Reset this embedder's entry to default for each of the requesting 966 // origins currently on the page. 967 const GURL& embedder_url = web_contents()->GetURL(); 968 TabSpecificContentSettings* content_settings = 969 TabSpecificContentSettings::FromWebContents(web_contents()); 970 const ContentSettingsUsagesState::StateMap& state_map = 971 content_settings->geolocation_usages_state().state_map(); 972 HostContentSettingsMap* settings_map = 973 profile()->GetHostContentSettingsMap(); 974 975 for (ContentSettingsUsagesState::StateMap::const_iterator it = 976 state_map.begin(); it != state_map.end(); ++it) { 977 settings_map->SetContentSetting( 978 ContentSettingsPattern::FromURLNoWildcard(it->first), 979 ContentSettingsPattern::FromURLNoWildcard(embedder_url), 980 CONTENT_SETTINGS_TYPE_GEOLOCATION, 981 std::string(), 982 CONTENT_SETTING_DEFAULT); 983 } 984 } 985 986 class ContentSettingMixedScriptBubbleModel 987 : public ContentSettingTitleLinkAndCustomModel { 988 public: 989 ContentSettingMixedScriptBubbleModel(Delegate* delegate, 990 WebContents* web_contents, 991 Profile* profile, 992 ContentSettingsType content_type); 993 994 virtual ~ContentSettingMixedScriptBubbleModel() {} 995 996 private: 997 virtual void OnCustomLinkClicked() OVERRIDE; 998 }; 999 1000 ContentSettingMixedScriptBubbleModel::ContentSettingMixedScriptBubbleModel( 1001 Delegate* delegate, 1002 WebContents* web_contents, 1003 Profile* profile, 1004 ContentSettingsType content_type) 1005 : ContentSettingTitleLinkAndCustomModel( 1006 delegate, web_contents, profile, content_type) { 1007 DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_MIXEDSCRIPT); 1008 set_custom_link_enabled(true); 1009 } 1010 1011 void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() { 1012 content::RecordAction(UserMetricsAction("MixedScript_LoadAnyway_Bubble")); 1013 DCHECK(web_contents()); 1014 web_contents()->SendToAllFrames( 1015 new ChromeViewMsg_SetAllowRunningInsecureContent(MSG_ROUTING_NONE, true)); 1016 web_contents()->GetMainFrame()->Send(new ChromeViewMsg_ReloadFrame( 1017 web_contents()->GetMainFrame()->GetRoutingID())); 1018 } 1019 1020 ContentSettingRPHBubbleModel::ContentSettingRPHBubbleModel( 1021 Delegate* delegate, 1022 WebContents* web_contents, 1023 Profile* profile, 1024 ProtocolHandlerRegistry* registry, 1025 ContentSettingsType content_type) 1026 : ContentSettingTitleAndLinkModel( 1027 delegate, web_contents, profile, content_type), 1028 selected_item_(0), 1029 registry_(registry), 1030 pending_handler_(ProtocolHandler::EmptyProtocolHandler()), 1031 previous_handler_(ProtocolHandler::EmptyProtocolHandler()) { 1032 DCHECK_EQ(CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, content_type); 1033 1034 TabSpecificContentSettings* content_settings = 1035 TabSpecificContentSettings::FromWebContents(web_contents); 1036 pending_handler_ = content_settings->pending_protocol_handler(); 1037 previous_handler_ = content_settings->previous_protocol_handler(); 1038 1039 base::string16 protocol; 1040 if (pending_handler_.protocol() == "mailto") { 1041 protocol = l10n_util::GetStringUTF16( 1042 IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME); 1043 } else if (pending_handler_.protocol() == "webcal") { 1044 protocol = l10n_util::GetStringUTF16( 1045 IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME); 1046 } else { 1047 protocol = base::UTF8ToUTF16(pending_handler_.protocol()); 1048 } 1049 1050 // Note that we ignore the |title| parameter. 1051 if (previous_handler_.IsEmpty()) { 1052 set_title(l10n_util::GetStringFUTF8( 1053 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM, 1054 base::UTF8ToUTF16(pending_handler_.url().host()), 1055 protocol)); 1056 } else { 1057 set_title(l10n_util::GetStringFUTF8( 1058 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE, 1059 base::UTF8ToUTF16(pending_handler_.url().host()), 1060 protocol, 1061 base::UTF8ToUTF16(previous_handler_.url().host()))); 1062 } 1063 1064 std::string radio_allow_label = 1065 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_ACCEPT); 1066 std::string radio_deny_label = 1067 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_DENY); 1068 std::string radio_ignore_label = 1069 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_IGNORE); 1070 1071 GURL url = web_contents->GetURL(); 1072 RadioGroup radio_group; 1073 radio_group.url = url; 1074 1075 radio_group.radio_items.push_back(radio_allow_label); 1076 radio_group.radio_items.push_back(radio_deny_label); 1077 radio_group.radio_items.push_back(radio_ignore_label); 1078 ContentSetting setting = 1079 content_settings->pending_protocol_handler_setting(); 1080 if (setting == CONTENT_SETTING_ALLOW) 1081 radio_group.default_item = RPH_ALLOW; 1082 else if (setting == CONTENT_SETTING_BLOCK) 1083 radio_group.default_item = RPH_BLOCK; 1084 else 1085 radio_group.default_item = RPH_IGNORE; 1086 1087 selected_item_ = radio_group.default_item; 1088 set_radio_group_enabled(true); 1089 set_radio_group(radio_group); 1090 } 1091 1092 void ContentSettingRPHBubbleModel::OnRadioClicked(int radio_index) { 1093 if (selected_item_ == radio_index) 1094 return; 1095 1096 selected_item_ = radio_index; 1097 1098 if (radio_index == RPH_ALLOW) 1099 RegisterProtocolHandler(); 1100 else if (radio_index == RPH_BLOCK) 1101 UnregisterProtocolHandler(); 1102 else if (radio_index == RPH_IGNORE) 1103 IgnoreProtocolHandler(); 1104 else 1105 NOTREACHED(); 1106 } 1107 1108 void ContentSettingRPHBubbleModel::OnDoneClicked() { 1109 // The user has one chance to deal with the RPH content setting UI, 1110 // then we remove it. 1111 TabSpecificContentSettings::FromWebContents(web_contents())-> 1112 ClearPendingProtocolHandler(); 1113 content::NotificationService::current()->Notify( 1114 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 1115 content::Source<WebContents>(web_contents()), 1116 content::NotificationService::NoDetails()); 1117 } 1118 1119 void ContentSettingRPHBubbleModel::RegisterProtocolHandler() { 1120 // A no-op if the handler hasn't been ignored, but needed in case the user 1121 // selects sequences like register/ignore/register. 1122 registry_->RemoveIgnoredHandler(pending_handler_); 1123 1124 registry_->OnAcceptRegisterProtocolHandler(pending_handler_); 1125 TabSpecificContentSettings::FromWebContents(web_contents())-> 1126 set_pending_protocol_handler_setting(CONTENT_SETTING_ALLOW); 1127 } 1128 1129 void ContentSettingRPHBubbleModel::UnregisterProtocolHandler() { 1130 registry_->OnDenyRegisterProtocolHandler(pending_handler_); 1131 TabSpecificContentSettings::FromWebContents(web_contents())-> 1132 set_pending_protocol_handler_setting(CONTENT_SETTING_BLOCK); 1133 ClearOrSetPreviousHandler(); 1134 } 1135 1136 void ContentSettingRPHBubbleModel::IgnoreProtocolHandler() { 1137 registry_->OnIgnoreRegisterProtocolHandler(pending_handler_); 1138 TabSpecificContentSettings::FromWebContents(web_contents())-> 1139 set_pending_protocol_handler_setting(CONTENT_SETTING_DEFAULT); 1140 ClearOrSetPreviousHandler(); 1141 } 1142 1143 void ContentSettingRPHBubbleModel::ClearOrSetPreviousHandler() { 1144 if (previous_handler_.IsEmpty()) { 1145 registry_->ClearDefault(pending_handler_.protocol()); 1146 } else { 1147 registry_->OnAcceptRegisterProtocolHandler(previous_handler_); 1148 } 1149 } 1150 1151 class ContentSettingMidiSysExBubbleModel 1152 : public ContentSettingTitleAndLinkModel { 1153 public: 1154 ContentSettingMidiSysExBubbleModel(Delegate* delegate, 1155 WebContents* web_contents, 1156 Profile* profile, 1157 ContentSettingsType content_type); 1158 virtual ~ContentSettingMidiSysExBubbleModel() {} 1159 1160 private: 1161 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id); 1162 void SetDomainsAndCustomLink(); 1163 virtual void OnCustomLinkClicked() OVERRIDE; 1164 }; 1165 1166 ContentSettingMidiSysExBubbleModel::ContentSettingMidiSysExBubbleModel( 1167 Delegate* delegate, 1168 WebContents* web_contents, 1169 Profile* profile, 1170 ContentSettingsType content_type) 1171 : ContentSettingTitleAndLinkModel( 1172 delegate, web_contents, profile, content_type) { 1173 DCHECK_EQ(CONTENT_SETTINGS_TYPE_MIDI_SYSEX, content_type); 1174 SetDomainsAndCustomLink(); 1175 } 1176 1177 void ContentSettingMidiSysExBubbleModel::MaybeAddDomainList( 1178 const std::set<std::string>& hosts, int title_id) { 1179 if (!hosts.empty()) { 1180 DomainList domain_list; 1181 domain_list.title = l10n_util::GetStringUTF8(title_id); 1182 domain_list.hosts = hosts; 1183 add_domain_list(domain_list); 1184 } 1185 } 1186 1187 void ContentSettingMidiSysExBubbleModel::SetDomainsAndCustomLink() { 1188 TabSpecificContentSettings* content_settings = 1189 TabSpecificContentSettings::FromWebContents(web_contents()); 1190 const ContentSettingsUsagesState& usages_state = 1191 content_settings->midi_usages_state(); 1192 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state; 1193 unsigned int tab_state_flags = 0; 1194 usages_state.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags); 1195 // Divide the tab's current MIDI sysex users into sets according to their 1196 // permission state. 1197 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW], 1198 IDS_MIDI_SYSEX_BUBBLE_ALLOWED); 1199 1200 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK], 1201 IDS_MIDI_SYSEX_BUBBLE_DENIED); 1202 1203 if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) { 1204 set_custom_link(l10n_util::GetStringUTF8( 1205 IDS_MIDI_SYSEX_BUBBLE_CLEAR_LINK)); 1206 set_custom_link_enabled(true); 1207 } else if (tab_state_flags & 1208 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) { 1209 set_custom_link(l10n_util::GetStringUTF8( 1210 IDS_MIDI_SYSEX_BUBBLE_REQUIRE_RELOAD_TO_CLEAR)); 1211 } 1212 } 1213 1214 void ContentSettingMidiSysExBubbleModel::OnCustomLinkClicked() { 1215 if (!web_contents()) 1216 return; 1217 // Reset this embedder's entry to default for each of the requesting 1218 // origins currently on the page. 1219 TabSpecificContentSettings* content_settings = 1220 TabSpecificContentSettings::FromWebContents(web_contents()); 1221 const ContentSettingsUsagesState::StateMap& state_map = 1222 content_settings->midi_usages_state().state_map(); 1223 HostContentSettingsMap* settings_map = 1224 profile()->GetHostContentSettingsMap(); 1225 1226 for (ContentSettingsUsagesState::StateMap::const_iterator it = 1227 state_map.begin(); it != state_map.end(); ++it) { 1228 settings_map->SetContentSetting( 1229 ContentSettingsPattern::FromURLNoWildcard(it->first), 1230 ContentSettingsPattern::Wildcard(), 1231 CONTENT_SETTINGS_TYPE_MIDI_SYSEX, 1232 std::string(), 1233 CONTENT_SETTING_DEFAULT); 1234 } 1235 } 1236 1237 // static 1238 ContentSettingBubbleModel* 1239 ContentSettingBubbleModel::CreateContentSettingBubbleModel( 1240 Delegate* delegate, 1241 WebContents* web_contents, 1242 Profile* profile, 1243 ContentSettingsType content_type) { 1244 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) { 1245 return new ContentSettingCookiesBubbleModel(delegate, web_contents, profile, 1246 content_type); 1247 } 1248 if (content_type == CONTENT_SETTINGS_TYPE_POPUPS) { 1249 return new ContentSettingPopupBubbleModel(delegate, web_contents, profile, 1250 content_type); 1251 } 1252 if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) { 1253 return new ContentSettingDomainListBubbleModel(delegate, web_contents, 1254 profile, content_type); 1255 } 1256 if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) { 1257 return new ContentSettingMediaStreamBubbleModel(delegate, web_contents, 1258 profile); 1259 } 1260 if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) { 1261 return new ContentSettingPluginBubbleModel(delegate, web_contents, profile, 1262 content_type); 1263 } 1264 if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) { 1265 return new ContentSettingMixedScriptBubbleModel(delegate, web_contents, 1266 profile, content_type); 1267 } 1268 if (content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) { 1269 ProtocolHandlerRegistry* registry = 1270 ProtocolHandlerRegistryFactory::GetForBrowserContext(profile); 1271 return new ContentSettingRPHBubbleModel(delegate, web_contents, profile, 1272 registry, content_type); 1273 } 1274 if (content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) { 1275 return new ContentSettingMidiSysExBubbleModel(delegate, web_contents, 1276 profile, content_type); 1277 } 1278 return new ContentSettingSingleRadioGroup(delegate, web_contents, profile, 1279 content_type); 1280 } 1281 1282 ContentSettingBubbleModel::ContentSettingBubbleModel( 1283 WebContents* web_contents, 1284 Profile* profile, 1285 ContentSettingsType content_type) 1286 : web_contents_(web_contents), 1287 profile_(profile), 1288 content_type_(content_type), 1289 setting_is_managed_(false) { 1290 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 1291 content::Source<WebContents>(web_contents)); 1292 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, 1293 content::Source<Profile>(profile_)); 1294 } 1295 1296 ContentSettingBubbleModel::~ContentSettingBubbleModel() { 1297 } 1298 1299 ContentSettingBubbleModel::RadioGroup::RadioGroup() : default_item(0) {} 1300 1301 ContentSettingBubbleModel::RadioGroup::~RadioGroup() {} 1302 1303 ContentSettingBubbleModel::DomainList::DomainList() {} 1304 1305 ContentSettingBubbleModel::DomainList::~DomainList() {} 1306 1307 ContentSettingBubbleModel::MediaMenu::MediaMenu() : disabled(false) {} 1308 1309 ContentSettingBubbleModel::MediaMenu::~MediaMenu() {} 1310 1311 ContentSettingBubbleModel::BubbleContent::BubbleContent() 1312 : radio_group_enabled(false), 1313 custom_link_enabled(false) { 1314 } 1315 1316 ContentSettingBubbleModel::BubbleContent::~BubbleContent() {} 1317 1318 void ContentSettingBubbleModel::Observe( 1319 int type, 1320 const content::NotificationSource& source, 1321 const content::NotificationDetails& details) { 1322 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { 1323 DCHECK_EQ(web_contents_, 1324 content::Source<WebContents>(source).ptr()); 1325 web_contents_ = NULL; 1326 } else { 1327 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); 1328 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr()); 1329 profile_ = NULL; 1330 } 1331 } 1332