Home | History | Annotate | Download | only in content_settings
      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