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