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 #ifndef CHROME_BROWSER_UI_CONTENT_SETTINGS_CONTENT_SETTING_BUBBLE_MODEL_H_ 6 #define CHROME_BROWSER_UI_CONTENT_SETTINGS_CONTENT_SETTING_BUBBLE_MODEL_H_ 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <set> 12 #include <string> 13 #include <vector> 14 15 #include "base/compiler_specific.h" 16 #include "base/macros.h" 17 #include "base/scoped_observer.h" 18 #include "base/strings/string16.h" 19 #include "build/build_config.h" 20 #include "chrome/app/vector_icons/vector_icons.h" 21 #include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h" 22 #include "chrome/common/custom_handlers/protocol_handler.h" 23 #include "components/blocked_content/url_list_manager.h" 24 #include "components/content_settings/browser/page_specific_content_settings.h" 25 #include "components/content_settings/core/common/content_settings.h" 26 #include "components/content_settings/core/common/content_settings_types.h" 27 #include "third_party/blink/public/common/mediastream/media_stream_request.h" 28 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/gfx/image/image.h" 30 #include "url/gurl.h" 31 32 class ContentSettingBubbleModelDelegate; 33 class Profile; 34 class ProtocolHandlerRegistry; 35 36 namespace content { 37 class WebContents; 38 } 39 40 namespace rappor { 41 class RapporServiceImpl; 42 } 43 44 namespace ui { 45 class Event; 46 } 47 48 // The hierarchy of bubble models: 49 // 50 // ContentSettingBubbleModel - base class 51 // ContentSettingSimpleBubbleModel - single content setting 52 // ContentSettingMixedScriptBubbleModel - mixed script 53 // ContentSettingRPHBubbleModel - protocol handlers 54 // ContentSettingPluginBubbleModel - plugins 55 // ContentSettingSingleRadioGroup - radio group 56 // ContentSettingCookiesBubbleModel - cookies 57 // ContentSettingPopupBubbleModel - popups 58 // ContentSettingFramebustBlockBubbleModel - blocked frame busting 59 // ContentSettingMediaStreamBubbleModel - media (camera and mic) 60 // ContentSettingSubresourceFilterBubbleModel - filtered subresources 61 // ContentSettingDownloadsBubbleModel - automatic downloads 62 // ContentSettingNotificationsBubbleModel - notifications 63 64 // Forward declaration necessary for downcasts. 65 class ContentSettingSimpleBubbleModel; 66 class ContentSettingMediaStreamBubbleModel; 67 class ContentSettingSubresourceFilterBubbleModel; 68 class ContentSettingDownloadsBubbleModel; 69 class ContentSettingFramebustBlockBubbleModel; 70 class ContentSettingNotificationsBubbleModel; 71 72 // This model provides data for ContentSettingBubble, and also controls 73 // the action triggered when the allow / block radio buttons are triggered. 74 class ContentSettingBubbleModel { 75 public: 76 typedef ContentSettingBubbleModelDelegate Delegate; 77 78 struct ListItem { 79 ListItem(const gfx::VectorIcon* image, 80 const base::string16& title, 81 const base::string16& description, 82 bool has_link, 83 bool has_blocked_badge, 84 int32_t item_id); 85 ListItem(const ListItem& other); 86 ListItem& operator=(const ListItem& other); 87 const gfx::VectorIcon* image; 88 base::string16 title; 89 base::string16 description; 90 bool has_link; 91 bool has_blocked_badge; 92 int32_t item_id; 93 }; 94 typedef std::vector<ListItem> ListItems; 95 96 class Owner { 97 public: OnListItemAdded(const ListItem & item)98 virtual void OnListItemAdded(const ListItem& item) {} OnListItemRemovedAt(int index)99 virtual void OnListItemRemovedAt(int index) {} 100 virtual int GetSelectedRadioOption() = 0; 101 102 protected: 103 virtual ~Owner() = default; 104 }; 105 106 typedef std::vector<base::string16> RadioItems; 107 struct RadioGroup { 108 RadioGroup(); 109 ~RadioGroup(); 110 111 GURL url; 112 RadioItems radio_items; 113 int default_item; 114 115 // Whether the user can control this radio group. False if controlled by 116 // policy, etc. 117 bool user_managed = true; 118 }; 119 120 struct DomainList { 121 DomainList(); 122 DomainList(const DomainList& other); 123 ~DomainList(); 124 125 base::string16 title; 126 std::set<std::string> hosts; 127 }; 128 129 struct MediaMenu { 130 MediaMenu(); 131 MediaMenu(const MediaMenu& other); 132 ~MediaMenu(); 133 134 base::string16 label; 135 blink::MediaStreamDevice default_device; 136 blink::MediaStreamDevice selected_device; 137 bool disabled; 138 }; 139 typedef std::map<blink::mojom::MediaStreamType, MediaMenu> MediaMenuMap; 140 141 enum class ManageTextStyle { 142 // No Manage button or checkbox is displayed. 143 kNone, 144 // Manage text is displayed as a non-prominent button. 145 kButton, 146 // Manage text is used as a checkbox title. 147 kCheckbox, 148 }; 149 150 struct BubbleContent { 151 BubbleContent(); 152 ~BubbleContent(); 153 154 base::string16 title; 155 base::string16 message; 156 ListItems list_items; 157 RadioGroup radio_group; 158 std::vector<DomainList> domain_lists; 159 base::string16 custom_link; 160 bool custom_link_enabled = false; 161 base::string16 manage_text; 162 ManageTextStyle manage_text_style = ManageTextStyle::kButton; 163 MediaMenuMap media_menus; 164 bool show_learn_more = false; 165 base::string16 done_button_text; 166 base::string16 cancel_button_text; 167 168 private: 169 DISALLOW_COPY_AND_ASSIGN(BubbleContent); 170 }; 171 172 static const int kAllowButtonIndex; 173 174 // Creates a bubble model for a particular |content_type|. Note that not all 175 // bubbles fit this description. 176 // TODO(msramek): Move this to ContentSettingSimpleBubbleModel or remove 177 // entirely. 178 static std::unique_ptr<ContentSettingBubbleModel> 179 CreateContentSettingBubbleModel(Delegate* delegate, 180 content::WebContents* web_contents, 181 ContentSettingsType content_type); 182 183 virtual ~ContentSettingBubbleModel(); 184 bubble_content()185 const BubbleContent& bubble_content() const { return bubble_content_; } 186 set_owner(Owner * owner)187 void set_owner(Owner* owner) { owner_ = owner; } 188 OnListItemClicked(int index,const ui::Event & event)189 virtual void OnListItemClicked(int index, const ui::Event& event) {} OnCustomLinkClicked()190 virtual void OnCustomLinkClicked() {} OnManageButtonClicked()191 virtual void OnManageButtonClicked() {} OnManageCheckboxChecked(bool is_checked)192 virtual void OnManageCheckboxChecked(bool is_checked) {} OnLearnMoreClicked()193 virtual void OnLearnMoreClicked() {} OnMediaMenuClicked(blink::mojom::MediaStreamType type,const std::string & selected_device_id)194 virtual void OnMediaMenuClicked(blink::mojom::MediaStreamType type, 195 const std::string& selected_device_id) {} OnDoneButtonClicked()196 virtual void OnDoneButtonClicked() {} OnCancelButtonClicked()197 virtual void OnCancelButtonClicked() {} 198 // Called by the view code when the bubble is closed CommitChanges()199 virtual void CommitChanges() {} 200 201 // TODO(msramek): The casting methods below are only necessary because 202 // ContentSettingBubbleController in the Cocoa UI needs to know the type of 203 // the bubble it wraps. Find a solution that does not require reflection nor 204 // recreating the entire hierarchy for Cocoa UI. 205 // Cast this bubble into ContentSettingSimpleBubbleModel if possible. 206 virtual ContentSettingSimpleBubbleModel* AsSimpleBubbleModel(); 207 208 // Cast this bubble into ContentSettingMediaStreamBubbleModel if possible. 209 virtual ContentSettingMediaStreamBubbleModel* AsMediaStreamBubbleModel(); 210 211 // Cast this bubble into ContentSettingSubresourceFilterBubbleModel 212 // if possible. 213 virtual ContentSettingSubresourceFilterBubbleModel* 214 AsSubresourceFilterBubbleModel(); 215 216 // Cast this bubble into ContentSettingDownloadsBubbleModel if possible. 217 virtual ContentSettingDownloadsBubbleModel* AsDownloadsBubbleModel(); 218 219 // Cast this bubble into ContentSettingFramebustBlockBubbleModel if possible. 220 virtual ContentSettingFramebustBlockBubbleModel* 221 AsFramebustBlockBubbleModel(); 222 223 // Cast this bubble into ContentSettingNotificationsBubbleModel if possible. 224 virtual ContentSettingNotificationsBubbleModel* AsNotificationsBubbleModel(); 225 226 // Sets the Rappor service used for testing. SetRapporServiceImplForTesting(rappor::RapporServiceImpl * rappor_service)227 void SetRapporServiceImplForTesting( 228 rappor::RapporServiceImpl* rappor_service) { 229 rappor_service_ = rappor_service; 230 } 231 232 protected: 233 // |web_contents| must outlive this. 234 ContentSettingBubbleModel(Delegate* delegate, 235 content::WebContents* web_contents); 236 237 // Should always be non-nullptr. web_contents()238 content::WebContents* web_contents() const { return web_contents_; } 239 Profile* GetProfile() const; delegate()240 Delegate* delegate() const { return delegate_; } selected_item()241 int selected_item() const { return owner_->GetSelectedRadioOption(); } 242 set_title(const base::string16 & title)243 void set_title(const base::string16& title) { bubble_content_.title = title; } set_message(const base::string16 & message)244 void set_message(const base::string16& message) { 245 bubble_content_.message = message; 246 } clear_message()247 void clear_message() { bubble_content_.message.clear(); } 248 void AddListItem(const ListItem& item); 249 void RemoveListItem(int index); set_radio_group(const RadioGroup & radio_group)250 void set_radio_group(const RadioGroup& radio_group) { 251 bubble_content_.radio_group = radio_group; 252 } add_domain_list(const DomainList & domain_list)253 void add_domain_list(const DomainList& domain_list) { 254 bubble_content_.domain_lists.push_back(domain_list); 255 } set_custom_link(const base::string16 & link)256 void set_custom_link(const base::string16& link) { 257 bubble_content_.custom_link = link; 258 } set_custom_link_enabled(bool enabled)259 void set_custom_link_enabled(bool enabled) { 260 bubble_content_.custom_link_enabled = enabled; 261 } set_manage_text(const base::string16 & text)262 void set_manage_text(const base::string16& text) { 263 bubble_content_.manage_text = text; 264 } set_manage_text_style(ManageTextStyle manage_text_style)265 void set_manage_text_style(ManageTextStyle manage_text_style) { 266 bubble_content_.manage_text_style = manage_text_style; 267 } add_media_menu(blink::mojom::MediaStreamType type,const MediaMenu & menu)268 void add_media_menu(blink::mojom::MediaStreamType type, 269 const MediaMenu& menu) { 270 bubble_content_.media_menus[type] = menu; 271 } set_selected_device(const blink::MediaStreamDevice & device)272 void set_selected_device(const blink::MediaStreamDevice& device) { 273 bubble_content_.media_menus[device.type].selected_device = device; 274 } set_show_learn_more(bool show_learn_more)275 void set_show_learn_more(bool show_learn_more) { 276 bubble_content_.show_learn_more = show_learn_more; 277 } set_done_button_text(const base::string16 & done_button_text)278 void set_done_button_text(const base::string16& done_button_text) { 279 bubble_content_.done_button_text = done_button_text; 280 } set_cancel_button_text(const base::string16 & cancel_button_text)281 void set_cancel_button_text(const base::string16& cancel_button_text) { 282 bubble_content_.cancel_button_text = cancel_button_text; 283 } rappor_service()284 rappor::RapporServiceImpl* rappor_service() const { return rappor_service_; } 285 286 private: 287 content::WebContents* web_contents_; 288 Owner* owner_; 289 Delegate* delegate_; 290 BubbleContent bubble_content_; 291 // The service used to record Rappor metrics. Can be set for testing. 292 rappor::RapporServiceImpl* rappor_service_; 293 294 DISALLOW_COPY_AND_ASSIGN(ContentSettingBubbleModel); 295 }; 296 297 // A generic bubble used for a single content setting. 298 class ContentSettingSimpleBubbleModel : public ContentSettingBubbleModel { 299 public: 300 ContentSettingSimpleBubbleModel(Delegate* delegate, 301 content::WebContents* web_contents, 302 ContentSettingsType content_type); 303 content_type()304 ContentSettingsType content_type() { return content_type_; } 305 306 // ContentSettingBubbleModel implementation. 307 ContentSettingSimpleBubbleModel* AsSimpleBubbleModel() override; 308 309 private: 310 FRIEND_TEST_ALL_PREFIXES(FramebustBlockBrowserTest, ManageButtonClicked); 311 312 // ContentSettingBubbleModel implementation. 313 void SetTitle(); 314 void SetMessage(); 315 void SetManageText(); 316 void OnManageButtonClicked() override; 317 void SetCustomLink(); 318 void OnCustomLinkClicked() override; 319 320 ContentSettingsType content_type_; 321 322 DISALLOW_COPY_AND_ASSIGN(ContentSettingSimpleBubbleModel); 323 }; 324 325 // RPH stands for Register Protocol Handler. 326 class ContentSettingRPHBubbleModel : public ContentSettingSimpleBubbleModel { 327 public: 328 ContentSettingRPHBubbleModel(Delegate* delegate, 329 content::WebContents* web_contents, 330 ProtocolHandlerRegistry* registry); 331 ~ContentSettingRPHBubbleModel() override; 332 333 // ContentSettingBubbleModel: 334 void CommitChanges() override; 335 336 private: 337 void RegisterProtocolHandler(); 338 void UnregisterProtocolHandler(); 339 void IgnoreProtocolHandler(); 340 void ClearOrSetPreviousHandler(); 341 void PerformActionForSelectedItem(); 342 343 ProtocolHandlerRegistry* registry_; 344 ProtocolHandler pending_handler_; 345 ProtocolHandler previous_handler_; 346 347 DISALLOW_COPY_AND_ASSIGN(ContentSettingRPHBubbleModel); 348 }; 349 350 // The model of the content settings bubble for media settings. 351 class ContentSettingMediaStreamBubbleModel : public ContentSettingBubbleModel { 352 public: 353 ContentSettingMediaStreamBubbleModel(Delegate* delegate, 354 content::WebContents* web_contents); 355 356 ~ContentSettingMediaStreamBubbleModel() override; 357 358 // ContentSettingBubbleModel: 359 ContentSettingMediaStreamBubbleModel* AsMediaStreamBubbleModel() override; 360 void CommitChanges() override; 361 void OnManageButtonClicked() override; 362 void OnDoneButtonClicked() override; 363 364 private: 365 // Helper functions to check if this bubble was invoked for microphone, 366 // camera, or both devices. 367 bool MicrophoneAccessed() const; 368 bool CameraAccessed() const; 369 370 bool MicrophoneBlocked() const; 371 bool CameraBlocked() const; 372 373 void SetTitle(); 374 void SetMessage(); 375 void SetManageText(); 376 377 // Sets the data for the radio buttons of the bubble. 378 void SetRadioGroup(); 379 380 // Sets the data for the media menus of the bubble. 381 void SetMediaMenus(); 382 383 // Sets the string that suggests reloading after the settings were changed. 384 void SetCustomLink(); 385 386 // Updates the camera and microphone setting with the passed |setting|. 387 void UpdateSettings(ContentSetting setting); 388 389 #if defined(OS_MAC) 390 // Initialize the bubble with the elements specific to the scenario when 391 // camera or mic are disabled in a system (OS) level. 392 void InitializeSystemMediaPermissionBubble(); 393 #endif // defined(OS_MAC) 394 395 // Whether or not to show the bubble UI specific to when media permissions are 396 // turned off in a system level. 397 bool ShouldShowSystemMediaPermissions(); 398 399 // Updates the camera and microphone default device with the passed |type| 400 // and device. 401 void UpdateDefaultDeviceForType(blink::mojom::MediaStreamType type, 402 const std::string& device); 403 404 // ContentSettingBubbleModel implementation. 405 void OnMediaMenuClicked(blink::mojom::MediaStreamType type, 406 const std::string& selected_device) override; 407 408 // The content settings that are associated with the individual radio 409 // buttons. 410 ContentSetting radio_item_setting_[2]; 411 // The state of the microphone and camera access. 412 content_settings::PageSpecificContentSettings::MicrophoneCameraState state_; 413 414 DISALLOW_COPY_AND_ASSIGN(ContentSettingMediaStreamBubbleModel); 415 }; 416 417 // The model of a bubble that acts as a quiet permission request prompt for 418 // notifications. In contrast to other bubbles (which display the current 419 // permission state after the user makes the initial decision), this is shown 420 // before the user makes the first ever permission decisions. 421 class ContentSettingNotificationsBubbleModel 422 : public ContentSettingBubbleModel { 423 public: 424 ContentSettingNotificationsBubbleModel(Delegate* delegate, 425 content::WebContents* web_contents); 426 427 ~ContentSettingNotificationsBubbleModel() override; 428 429 private: 430 void SetManageText(); 431 432 // ContentSettingBubbleModel: 433 void OnManageButtonClicked() override; 434 void OnLearnMoreClicked() override; 435 void OnDoneButtonClicked() override; 436 void OnCancelButtonClicked() override; 437 ContentSettingNotificationsBubbleModel* AsNotificationsBubbleModel() override; 438 439 DISALLOW_COPY_AND_ASSIGN(ContentSettingNotificationsBubbleModel); 440 }; 441 442 // The model for the deceptive content bubble. 443 class ContentSettingSubresourceFilterBubbleModel 444 : public ContentSettingBubbleModel { 445 public: 446 ContentSettingSubresourceFilterBubbleModel( 447 Delegate* delegate, 448 content::WebContents* web_contents); 449 450 ~ContentSettingSubresourceFilterBubbleModel() override; 451 452 private: 453 void SetMessage(); 454 void SetTitle(); 455 void SetManageText(); 456 457 // ContentSettingBubbleModel: 458 void OnManageCheckboxChecked(bool is_checked) override; 459 ContentSettingSubresourceFilterBubbleModel* AsSubresourceFilterBubbleModel() 460 override; 461 void OnLearnMoreClicked() override; 462 void CommitChanges() override; 463 464 bool is_checked_ = false; 465 466 DISALLOW_COPY_AND_ASSIGN(ContentSettingSubresourceFilterBubbleModel); 467 }; 468 469 // The model for automatic downloads setting. 470 class ContentSettingDownloadsBubbleModel : public ContentSettingBubbleModel { 471 public: 472 ContentSettingDownloadsBubbleModel(Delegate* delegate, 473 content::WebContents* web_contents); 474 ~ContentSettingDownloadsBubbleModel() override; 475 476 // ContentSettingBubbleModel overrides: 477 ContentSettingDownloadsBubbleModel* AsDownloadsBubbleModel() override; 478 void CommitChanges() override; 479 480 private: 481 void SetRadioGroup(); 482 void SetTitle(); 483 void SetManageText(); 484 485 // ContentSettingBubbleModel overrides: 486 void OnManageButtonClicked() override; 487 488 DISALLOW_COPY_AND_ASSIGN(ContentSettingDownloadsBubbleModel); 489 }; 490 491 class ContentSettingSingleRadioGroup : public ContentSettingSimpleBubbleModel { 492 public: 493 ContentSettingSingleRadioGroup(Delegate* delegate, 494 content::WebContents* web_contents, 495 ContentSettingsType content_type); 496 ~ContentSettingSingleRadioGroup() override; 497 498 // ContentSettingSimpleBubbleModel: 499 void CommitChanges() override; 500 501 protected: 502 bool settings_changed() const; 503 504 private: 505 FRIEND_TEST_ALL_PREFIXES(FramebustBlockBrowserTest, AllowRadioButtonSelected); 506 FRIEND_TEST_ALL_PREFIXES(FramebustBlockBrowserTest, 507 DisallowRadioButtonSelected); 508 509 void SetRadioGroup(); 510 void SetNarrowestContentSetting(ContentSetting setting); 511 512 ContentSetting block_setting_; 513 514 DISALLOW_COPY_AND_ASSIGN(ContentSettingSingleRadioGroup); 515 }; 516 517 // The bubble that informs users that Chrome does not have access to Location 518 // and guides them to the system preferences to fix that problem if they wish. 519 class ContentSettingGeolocationBubbleModel 520 : public ContentSettingSingleRadioGroup { 521 public: 522 ContentSettingGeolocationBubbleModel(Delegate* delegate, 523 content::WebContents* web_contents); 524 525 ContentSettingGeolocationBubbleModel( 526 const ContentSettingGeolocationBubbleModel&) = delete; 527 ContentSettingGeolocationBubbleModel& operator=( 528 const ContentSettingGeolocationBubbleModel&) = delete; 529 530 ~ContentSettingGeolocationBubbleModel() override; 531 532 // ContentSettingBubbleModel: 533 void OnManageButtonClicked() override; 534 void OnDoneButtonClicked() override; 535 void CommitChanges() override; 536 537 private: 538 // Initialize the bubble with the elements specific to the scenario when 539 // geolocation is disabled on the system (OS) level. 540 void InitializeSystemGeolocationPermissionBubble(); 541 void SetCustomLink(); 542 543 // Whether or not we are showing the bubble UI specific to when geolocation 544 // permissions are turned off on a system level. 545 bool show_system_geolocation_bubble_ = false; 546 }; 547 548 #if !defined(OS_ANDROID) 549 // The model for the blocked Framebust bubble. 550 class ContentSettingFramebustBlockBubbleModel 551 : public ContentSettingSingleRadioGroup, 552 public blocked_content::UrlListManager::Observer { 553 public: 554 ContentSettingFramebustBlockBubbleModel(Delegate* delegate, 555 content::WebContents* web_contents); 556 557 ~ContentSettingFramebustBlockBubbleModel() override; 558 559 // ContentSettingBubbleModel: 560 void OnListItemClicked(int index, const ui::Event& event) override; 561 ContentSettingFramebustBlockBubbleModel* AsFramebustBlockBubbleModel() 562 override; 563 564 // UrlListManager::Observer: 565 void BlockedUrlAdded(int32_t id, const GURL& blocked_url) override; 566 567 private: 568 ListItem CreateListItem(const GURL& url); 569 570 ScopedObserver<blocked_content::UrlListManager, 571 blocked_content::UrlListManager::Observer> 572 url_list_observer_; 573 574 DISALLOW_COPY_AND_ASSIGN(ContentSettingFramebustBlockBubbleModel); 575 }; 576 #endif // !defined(OS_ANDROID) 577 578 #endif // CHROME_BROWSER_UI_CONTENT_SETTINGS_CONTENT_SETTING_BUBBLE_MODEL_H_ 579