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