Update PageNode content settings when they change

Bug: 1370699
Change-Id: I490f589914cd03598a5c098e3d6d829e88871db4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3949359
Reviewed-by: Patrick Monette <pmonette@chromium.org>
Commit-Queue: Anthony Vallée-Dubois <anthonyvd@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1058319}
diff --git a/chrome/browser/performance_manager/decorators/helpers/page_live_state_decorator_helper.cc b/chrome/browser/performance_manager/decorators/helpers/page_live_state_decorator_helper.cc
index 2de52a2..b4967c779 100644
--- a/chrome/browser/performance_manager/decorators/helpers/page_live_state_decorator_helper.cc
+++ b/chrome/browser/performance_manager/decorators/helpers/page_live_state_decorator_helper.cc
@@ -7,8 +7,14 @@
 #include "base/memory/raw_ptr.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
+#include "components/content_settings/core/browser/content_settings_observer.h"
+#include "components/content_settings/core/browser/content_settings_type_set.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
+#include "components/content_settings/core/common/content_settings_types.h"
 #include "components/performance_manager/public/decorators/page_live_state_decorator.h"
 #include "components/performance_manager/public/performance_manager.h"
+#include "components/permissions/permissions_client.h"
 #include "content/public/browser/web_contents_observer.h"
 
 #if !BUILDFLAG(IS_ANDROID)
@@ -78,7 +84,8 @@
 // and updates the PageLiveStateDecorator accordingly. Destroys itself when the
 // WebContents it observes is destroyed.
 class PageLiveStateDecoratorHelper::WebContentsObserver
-    : public content::WebContentsObserver {
+    : public content::WebContentsObserver,
+      public content_settings::Observer {
  public:
   explicit WebContentsObserver(content::WebContents* web_contents,
                                PageLiveStateDecoratorHelper* outer)
@@ -92,6 +99,10 @@
       next_->prev_ = this;
     }
     outer_->first_web_contents_observer_ = this;
+
+    content_settings_observation_.Observe(
+        permissions::PermissionsClient::Get()->GetSettingsMap(
+            web_contents->GetBrowserContext()));
   }
 
   WebContentsObserver(const WebContentsObserver&) = delete;
@@ -101,6 +112,28 @@
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   }
 
+  // content_settings::Observer:
+  void OnContentSettingChanged(
+      const ContentSettingsPattern& primary_pattern,
+      const ContentSettingsPattern& secondary_pattern,
+      ContentSettingsTypeSet content_type_set) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    GURL url = web_contents()->GetLastCommittedURL();
+    if (content_type_set.Contains(ContentSettingsType::NOTIFICATIONS) &&
+        primary_pattern.Matches(url)) {
+      // This web contents is affected by this content settings change, get the
+      // latest value and send it over to the PageLiveStateDecorator so it can
+      // be attached to the corresponding PageNode.
+      ContentSetting setting =
+          permissions::PermissionsClient::Get()
+              ->GetSettingsMap(web_contents()->GetBrowserContext())
+              ->GetContentSetting(url, url, ContentSettingsType::NOTIFICATIONS);
+
+      PageLiveStateDecorator::SetContentSettings(
+          web_contents(), {{ContentSettingsType::NOTIFICATIONS, setting}});
+    }
+  }
+
   // content::WebContentsObserver:
   void OnIsConnectedToBluetoothDeviceChanged(
       bool is_connected_to_bluetooth_device) override {
@@ -144,6 +177,9 @@
   raw_ptr<WebContentsObserver> prev_;
   raw_ptr<WebContentsObserver> next_;
 
+  base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
+      content_settings_observation_{this};
+
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
diff --git a/chrome/browser/performance_manager/decorators/helpers/page_live_state_decorator_helper_unittest.cc b/chrome/browser/performance_manager/decorators/helpers/page_live_state_decorator_helper_unittest.cc
index 419bb0c..ca63b7d 100644
--- a/chrome/browser/performance_manager/decorators/helpers/page_live_state_decorator_helper_unittest.cc
+++ b/chrome/browser/performance_manager/decorators/helpers/page_live_state_decorator_helper_unittest.cc
@@ -6,9 +6,11 @@
 
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/performance_manager/embedder/performance_manager_registry.h"
 #include "components/performance_manager/performance_manager_impl.h"
 #include "components/performance_manager/public/decorators/page_live_state_decorator.h"
@@ -196,6 +198,73 @@
       &PageLiveStateDecorator::Data::IsConnectedToUSBDevice, false);
 }
 
+TEST_F(PageLiveStateDecoratorHelperTest, ContentSettingsChanged) {
+  base::WeakPtr<PageNode> node =
+      PerformanceManager::GetPrimaryPageNodeForWebContents(web_contents());
+  content::WebContentsTester::For(web_contents())
+      ->NavigateAndCommit(GURL("https://www.example.com/path"));
+
+  {
+    base::RunLoop run_loop;
+    PerformanceManager::CallOnGraph(
+        FROM_HERE, base::BindLambdaForTesting([&]() {
+          ASSERT_TRUE(node);
+          const PageLiveStateDecorator::Data* data =
+              PageLiveStateDecorator::Data::FromPageNode(node.get());
+          ASSERT_TRUE(data);
+          EXPECT_EQ(data->IsContentSettingTypeAllowed(
+                        ContentSettingsType::NOTIFICATIONS),
+                    false);
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+  }
+
+  HostContentSettingsMap* host_content_settings_map =
+      HostContentSettingsMapFactory::GetForProfile(
+          web_contents()->GetBrowserContext());
+  host_content_settings_map->SetContentSettingDefaultScope(
+      GURL("https://www.example.com/"), GURL(),
+      ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_ALLOW);
+
+  {
+    base::RunLoop run_loop;
+    PerformanceManager::CallOnGraph(
+        FROM_HERE, base::BindLambdaForTesting([&]() {
+          ASSERT_TRUE(node);
+          const PageLiveStateDecorator::Data* data =
+              PageLiveStateDecorator::Data::FromPageNode(node.get());
+          ASSERT_TRUE(data);
+          EXPECT_EQ(data->IsContentSettingTypeAllowed(
+                        ContentSettingsType::NOTIFICATIONS),
+                    true);
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+  }
+
+  // Changing content settings for a different URL doesn't affect this one.
+  host_content_settings_map->SetContentSettingDefaultScope(
+      GURL("https://other.url.com/"), GURL(),
+      ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_BLOCK);
+
+  {
+    base::RunLoop run_loop;
+    PerformanceManager::CallOnGraph(
+        FROM_HERE, base::BindLambdaForTesting([&]() {
+          ASSERT_TRUE(node);
+          const PageLiveStateDecorator::Data* data =
+              PageLiveStateDecorator::Data::FromPageNode(node.get());
+          ASSERT_TRUE(data);
+          EXPECT_EQ(data->IsContentSettingTypeAllowed(
+                        ContentSettingsType::NOTIFICATIONS),
+                    true);
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+  }
+}
+
 // Create many WebContents to exercice the code that maintains the linked list
 // of PageLiveStateDecoratorHelper::WebContentsObservers.
 TEST_F(PageLiveStateDecoratorHelperTest, ManyPageNodes) {