diff --git a/DEPS b/DEPS
index 170b0a3..940b8bf 100644
--- a/DEPS
+++ b/DEPS
@@ -394,7 +394,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'd240b7de4d30af0769390eea62a27c1e648e8401',
+  'devtools_frontend_revision': '646e7ba054335255c4186c6be09fee796b518b48',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -1609,7 +1609,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '722cdc7d46bd7c87d9b93b991d5ae1cc55205a0e',
+    '2f030b8b2858ba5b64842bf5a6268933929fddec',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
index f61d02d..ff114ecb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
@@ -269,8 +269,6 @@
     private final Observer mObserver;
     private final TileRenderer mTileRenderer;
     private final CustomTileModificationDelegate mCustomTileModificationDelegate;
-    // Used for TileInteractionDelegateImpl.
-    private final int mPrerenderDelay;
 
     /**
      * Tracks the tasks currently in flight.
@@ -309,7 +307,6 @@
                             mTileGroupDelegate,
                             mTileDragDelegate,
                             mCustomTileModificationDelegate,
-                            mPrerenderDelay,
                             tile,
                             view);
                 }
@@ -359,8 +356,6 @@
         mOfflineModelObserver = new OfflineModelObserver(offlinePageBridge);
         mUiDelegate.addDestructionObserver(mOfflineModelObserver);
         mCustomTileModificationDelegate = new CustomTileModificationDelegateImpl();
-
-        mPrerenderDelay = 0;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileInteractionDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileInteractionDelegateImpl.java
index f6e6082..270f97f1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileInteractionDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileInteractionDelegateImpl.java
@@ -42,7 +42,6 @@
     private final TileGroup.Delegate mTileGroupDelegate;
     private final TileDragDelegate mTileDragDelegate;
     private final TileGroup.CustomTileModificationDelegate mCustomTileModificationDelegate;
-    private final int mPrerenderDelay;
     private final Tile mTile;
     private final AndroidPrerenderManager mAndroidPrerenderManager;
 
@@ -57,14 +56,12 @@
             TileGroup.Delegate tileGroupDelegate,
             TileDragDelegate tileDragDelegate,
             TileGroup.CustomTileModificationDelegate customTileModificationDelegate,
-            int prerenderDelay,
             Tile tile,
             View view) {
         mContextMenuManager = contextMenuManager;
         mTileGroupDelegate = tileGroupDelegate;
         mTileDragDelegate = tileDragDelegate;
         mCustomTileModificationDelegate = customTileModificationDelegate;
-        mPrerenderDelay = prerenderDelay;
         mTile = tile;
 
         view.setOnClickListener(this);
@@ -105,7 +102,7 @@
                             }
                             mScheduldedPrerenderingUrl = null;
                         });
-        PostTask.postDelayedTask(TaskTraits.UI_DEFAULT, mPrerenderRunnable, mPrerenderDelay);
+        PostTask.postDelayedTask(TaskTraits.UI_DEFAULT, mPrerenderRunnable, 0);
     }
 
     // This function cancels scheduled prerendering or calls stopPrerendering to stop stale
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionUpdateMessageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionUpdateMessageTest.java
index 46c1286..21753db9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionUpdateMessageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionUpdateMessageTest.java
@@ -29,12 +29,9 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.browser.LocationSettingsTestUtil;
-import org.chromium.components.browser_ui.site_settings.GeolocationSetting;
-import org.chromium.components.browser_ui.site_settings.PermissionInfo;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridgeJni;
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
-import org.chromium.components.content_settings.SessionModel;
 import org.chromium.components.messages.MessageDispatcher;
 import org.chromium.components.messages.MessageDispatcherProvider;
 import org.chromium.components.messages.MessageIdentifier;
@@ -355,19 +352,6 @@
 
         final var windowAndroid = mActivityTestRule.getActivity().getWindowAndroid();
         final String locationUrl = mTestServer.getURL(GEOLOCATION_PAGE);
-        final PermissionInfo geolocationSettings =
-                ThreadUtils.runOnUiThreadBlocking(
-                        new Callable<>() {
-                            @Override
-                            public PermissionInfo call() {
-                                return new PermissionInfo(
-                                        getGeolocationType(),
-                                        locationUrl,
-                                        null,
-                                        /* isEmbargoed= */ false,
-                                        SessionModel.DURABLE);
-                            }
-                        });
 
         mActivityTestRule
                 .getActivity()
@@ -380,22 +364,7 @@
         LocationSettingsTestUtil.setSystemLocationSettingEnabled(true);
 
         try {
-            ThreadUtils.runOnUiThreadBlocking(
-                    () -> {
-                        if (geolocationSettings.getContentSettingsType()
-                                == ContentSettingsType.GEOLOCATION_WITH_OPTIONS) {
-                            geolocationSettings.setGeolocationSetting(
-                                    ProfileManager.getLastUsedRegularProfile(),
-                                    new GeolocationSetting(
-                                            ContentSettingValues.ALLOW,
-                                            ContentSettingValues.ALLOW));
-
-                        } else {
-                            geolocationSettings.setContentSetting(
-                                    ProfileManager.getLastUsedRegularProfile(),
-                                    ContentSettingValues.ALLOW);
-                        }
-                    });
+            setNativeContentSetting(getGeolocationType(), locationUrl, ContentSettingValues.ALLOW);
             mActivityTestRule.loadUrl(mTestServer.getURL(GEOLOCATION_PAGE));
             CriteriaHelper.pollUiThread(
                     () -> {
@@ -435,11 +404,8 @@
                                 Matchers.is(1));
                     });
         } finally {
-            ThreadUtils.runOnUiThreadBlocking(
-                    () ->
-                            geolocationSettings.setContentSetting(
-                                    ProfileManager.getLastUsedRegularProfile(),
-                                    ContentSettingValues.DEFAULT));
+            setNativeContentSetting(
+                    getGeolocationType(), locationUrl, ContentSettingValues.DEFAULT);
         }
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java
index 35743022..f69724b5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java
@@ -10,18 +10,23 @@
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.when;
 
+import androidx.preference.Preference;
 import androidx.test.filters.SmallTest;
 
-import org.junit.Assert;
+import org.chromium.chrome.test.util.browser.LocationSettingsTestUtil;
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -42,12 +47,15 @@
 import org.chromium.chrome.browser.profiles.ProfileManager;
 import org.chromium.chrome.browser.settings.SettingsActivity;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
+import org.chromium.chrome.test.R;
 import org.chromium.chrome.test.transit.AutoResetCtaTransitTestRule;
 import org.chromium.chrome.test.transit.ChromeTransitTestRules;
 import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
 import org.chromium.components.browser_ui.site_settings.ChosenObjectInfo;
 import org.chromium.components.browser_ui.site_settings.ContentSettingException;
 import org.chromium.components.browser_ui.site_settings.FileEditingInfo;
+import org.chromium.components.browser_ui.site_settings.GeolocationSetting;
+import org.chromium.components.browser_ui.site_settings.PermissionInfo;
 import org.chromium.components.browser_ui.site_settings.SingleWebsiteSettings;
 import org.chromium.components.browser_ui.site_settings.SiteSettingsDelegate;
 import org.chromium.components.browser_ui.site_settings.SiteSettingsUtil;
@@ -57,6 +65,9 @@
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
 import org.chromium.components.content_settings.ProviderType;
+import org.chromium.components.content_settings.SessionModel;
+import org.chromium.components.permissions.PermissionsAndroidFeatureList;
+import org.chromium.components.permissions.PermissionsAndroidFeatureMap;
 import org.chromium.media.MediaFeatures;
 import org.chromium.url.GURL;
 
@@ -81,17 +92,23 @@
 
     @Mock private SiteSettingsDelegate mSiteSettingsDelegate;
 
+    @Before
+    public void setUp() {
+        LocationSettingsTestUtil.setSystemLocationSettingEnabled(true);
+    }
+
     /** A provider supplying params for {@link #testExceptionToggleShowing}. */
     public static class SingleWebsiteSettingsParams implements ParameterProvider {
         @Override
         public Iterable<ParameterSet> getParameters() {
             ArrayList<ParameterSet> testCases = new ArrayList<>();
             for (@ContentSettingsType.EnumType
-            int contentSettings : SiteSettingsUtil.SETTINGS_ORDER) {
-                int enabled = SingleWebsiteSettings.getEnabledValue(contentSettings);
-                testCases.add(createParameterSet("Enabled_", contentSettings, enabled));
+            int contentSettingsType : SiteSettingsUtil.SETTINGS_ORDER) {
+                int enabled = SingleWebsiteSettings.getEnabledValue(contentSettingsType);
+                testCases.add(createParameterSet("Enabled_", contentSettingsType, enabled));
                 testCases.add(
-                        createParameterSet("Block_", contentSettings, ContentSettingValues.BLOCK));
+                        createParameterSet(
+                                "Block_", contentSettingsType, ContentSettingValues.BLOCK));
             }
             return testCases;
         }
@@ -108,6 +125,17 @@
         // SingleWebsiteSettings#setUpNotificationsPreference
         Assume.assumeFalse(contentSettingsType == ContentSettingsType.NOTIFICATIONS);
 
+        var approxGeoEnabled =
+                PermissionsAndroidFeatureMap.isEnabled(
+                        PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_PERMISSION);
+        if (contentSettingsType == ContentSettingsType.GEOLOCATION && approxGeoEnabled) {
+            return;
+        }
+        if (contentSettingsType == ContentSettingsType.GEOLOCATION_WITH_OPTIONS
+                && !approxGeoEnabled) {
+            return;
+        }
+
         new SingleExceptionTestCase(contentSettingsType, contentSettingValue).run();
     }
 
@@ -123,7 +151,7 @@
                 () -> {
                     SingleWebsiteSettings websitePreferences =
                             (SingleWebsiteSettings) settingsActivity.getMainFragment();
-                    Assert.assertNotNull(
+                    assertNotNull(
                             "Notification Preference not found.",
                             websitePreferences.findPreference(
                                     SingleWebsiteSettings.getPreferenceKey(
@@ -135,6 +163,101 @@
 
     @Test
     @SmallTest
+    @EnableFeatures(PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_PERMISSION)
+    public void testGeolocationPermission() {
+        GeolocationSetting allowSetting =
+                new GeolocationSetting(ContentSettingValues.ALLOW, ContentSettingValues.ALLOW);
+        GeolocationSetting blockSetting =
+                new GeolocationSetting(ContentSettingValues.BLOCK, ContentSettingValues.BLOCK);
+        runGeolocationTest(allowSetting, blockSetting, "Allowed", "Blocked");
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_PERMISSION)
+    public void testApproximateGeolocationPermission() {
+        GeolocationSetting allowSetting =
+                new GeolocationSetting(ContentSettingValues.ALLOW, ContentSettingValues.BLOCK);
+        GeolocationSetting blockSetting =
+                new GeolocationSetting(ContentSettingValues.BLOCK, ContentSettingValues.BLOCK);
+        runGeolocationTest(allowSetting, blockSetting, "Allowed • Approximate", "Blocked");
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_PERMISSION)
+    public void testOneTimeApproximateGeolocationPermission() {
+        GeolocationSetting allowSetting =
+                new GeolocationSetting(ContentSettingValues.ALLOW, ContentSettingValues.BLOCK);
+        GeolocationSetting askSetting =
+                new GeolocationSetting(ContentSettingValues.ASK, ContentSettingValues.ASK);
+
+        Website website =
+                createWebsiteWithGeolocationPermission(allowSetting, SessionModel.ONE_TIME);
+        SettingsActivity settingsActivity =
+                SiteSettingsTestUtils.startSingleWebsitePreferences(website);
+        var websitePreferences = (SingleWebsiteSettings) settingsActivity.getMainFragment();
+
+        // Check initial state
+        String preferenceKey =
+                SingleWebsiteSettings.getPreferenceKey(
+                        ContentSettingsType.GEOLOCATION_WITH_OPTIONS);
+        Preference preference = websitePreferences.findPreference(preferenceKey);
+        assertNotNull("Geolocation Preference not found.", preference);
+        assertEquals("Allowed this time • Approximate", preference.getSummary());
+        assertEquals(allowSetting, getGeolocationSetting(website));
+
+        // Delete one time permission.
+        onView(withId(R.id.image_view_widget)).perform(click());
+        assertNull(websitePreferences.findPreference(preferenceKey));
+        assertEquals(askSetting, getGeolocationSetting(website));
+
+        settingsActivity.finish();
+    }
+
+    private static void runGeolocationTest(
+            GeolocationSetting allowSetting,
+            GeolocationSetting blockSetting,
+            String allowedText,
+            String blockedText) {
+        Website website =
+                createWebsiteWithGeolocationPermission(allowSetting, SessionModel.DURABLE);
+        SettingsActivity settingsActivity =
+                SiteSettingsTestUtils.startSingleWebsitePreferences(website);
+        var websitePreferences = (SingleWebsiteSettings) settingsActivity.getMainFragment();
+
+        // Check initial state
+        String preferenceKey =
+                SingleWebsiteSettings.getPreferenceKey(
+                        ContentSettingsType.GEOLOCATION_WITH_OPTIONS);
+        Preference preference = websitePreferences.findPreference(preferenceKey);
+        assertNotNull("Geolocation Preference not found.", preference);
+        assertEquals(allowedText, preference.getSummary());
+        assertEquals(allowSetting, getGeolocationSetting(website));
+
+        // Change to block.
+        onView(withText(containsString("Location"))).perform(click());
+        assertEquals(blockedText, preference.getSummary());
+        assertEquals(blockSetting, getGeolocationSetting(website));
+
+        // Change back to allow.
+        onView(withText(containsString("Location"))).perform(click());
+        assertEquals(allowedText, preference.getSummary());
+        assertEquals(allowSetting, getGeolocationSetting(website));
+
+        settingsActivity.finish();
+    }
+
+    private static GeolocationSetting getGeolocationSetting(Website website) {
+        return ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    return website.getPermissionInfo(ContentSettingsType.GEOLOCATION_WITH_OPTIONS)
+                            .getGeolocationSetting(ProfileManager.getLastUsedRegularProfile());
+                });
+    }
+
+    @Test
+    @SmallTest
     public void testDesktopSiteException() {
         SettingsActivity settingsActivity =
                 SiteSettingsTestUtils.startSingleWebsitePreferences(
@@ -145,7 +268,7 @@
                 () -> {
                     var websitePreferences =
                             (SingleWebsiteSettings) settingsActivity.getMainFragment();
-                    Assert.assertNotNull(
+                    assertNotNull(
                             "Desktop site preference should be present.",
                             websitePreferences.findPreference(
                                     SingleWebsiteSettings.getPreferenceKey(
@@ -289,7 +412,7 @@
             @ContentSettingsType.EnumType int contentSettingsType,
             @ContentSettingValues int contentSettingValue) {
         String prefKey = SingleWebsiteSettings.getPreferenceKey(contentSettingsType);
-        Assert.assertNotNull(
+        assertNotNull(
                 "Preference key is missing for ContentSettingsType <" + contentSettingsType + ">.",
                 prefKey);
 
@@ -313,9 +436,17 @@
         }
 
         public void run() {
-            Website website =
-                    createWebsiteWithContentSettingException(
-                            mContentSettingsType, mContentSettingValue);
+            Website website;
+            if (mContentSettingsType == ContentSettingsType.GEOLOCATION_WITH_OPTIONS) {
+                website =
+                        createWebsiteWithGeolocationPermission(
+                                new GeolocationSetting(mContentSettingValue, mContentSettingValue),
+                                SessionModel.DURABLE);
+            } else {
+                website =
+                        createWebsiteWithContentSettingException(
+                                mContentSettingsType, mContentSettingValue);
+            }
             mSettingsActivity = SiteSettingsTestUtils.startSingleWebsitePreferences(website);
 
             ThreadUtils.runOnUiThreadBlocking(
@@ -331,7 +462,7 @@
         protected void doTest(SingleWebsiteSettings websitePreferences) {
             String prefKey = SingleWebsiteSettings.getPreferenceKey(mContentSettingsType);
             ChromeSwitchPreference switchPref = websitePreferences.findPreference(prefKey);
-            Assert.assertNotNull("Preference cannot be found on screen.", switchPref);
+            assertNotNull("Preference cannot be found on screen.", switchPref);
             assertEquals(
                     "Switch check state is different than test setting.",
                     mContentSettingValue
@@ -356,6 +487,25 @@
         return website;
     }
 
+    private static Website createWebsiteWithGeolocationPermission(
+            GeolocationSetting setting, int sessionModel) {
+        WebsiteAddress address = WebsiteAddress.create(EXAMPLE_ADDRESS);
+        Website website = new Website(address, address);
+        PermissionInfo info =
+                new PermissionInfo(
+                        ContentSettingsType.GEOLOCATION_WITH_OPTIONS,
+                        website.getAddress().getOrigin(),
+                        website.getAddress().getOrigin(),
+                        /* isEmbargoed= */ false,
+                        sessionModel);
+        ThreadUtils.runOnUiThreadBlocking(
+                () ->
+                        info.setGeolocationSetting(
+                                ProfileManager.getLastUsedRegularProfile(), setting));
+        website.setPermissionInfo(info);
+        return website;
+    }
+
     private static Website createWebsiteWithStorageAccessPermission(
             String origin, String embedder, @ContentSettingValues int setting) {
         Website website =
diff --git a/chrome/browser/policy/networking/network_configuration_updater_ash_unittest.cc b/chrome/browser/policy/networking/network_configuration_updater_ash_unittest.cc
index 37d2cf70..89e0a9af 100644
--- a/chrome/browser/policy/networking/network_configuration_updater_ash_unittest.cc
+++ b/chrome/browser/policy/networking/network_configuration_updater_ash_unittest.cc
@@ -128,19 +128,6 @@
     return count;
   }
 
-  void ImportAllCertificatesUserInitiated(
-      const std::vector<OncParsedCertificates::ServerOrAuthorityCertificate>&
-          server_or_authority_certificates,
-      const std::vector<OncParsedCertificates::ClientCertificate>&
-          client_certificates,
-      DoneCallback done_callback) override {
-    // As policy-provided server and authority certificates are not permanently
-    // imported, only ImportClientCertificaates should be called.
-    // ImportAllCertificatesUserInitiated should never be called from
-    // UserNetworkConfigurationUpdater.
-    NOTREACHED();
-  }
-
   void ImportClientCertificates(
       const std::vector<OncParsedCertificates::ClientCertificate>&
           client_certificates,
diff --git a/chrome/browser/ui/webui/history/history_sign_in_state_watcher_unittest.cc b/chrome/browser/ui/webui/history/history_sign_in_state_watcher_unittest.cc
new file mode 100644
index 0000000..fded6b8
--- /dev/null
+++ b/chrome/browser/ui/webui/history/history_sign_in_state_watcher_unittest.cc
@@ -0,0 +1,156 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/history/history_sign_in_state_watcher.h"
+
+#include "base/functional/bind.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
+#include "components/sync/base/features.h"
+#include "components/sync/test/test_sync_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using testing::StrictMock;
+
+class HistorySignInStateWatcherTestBase : public testing::Test {
+ public:
+  explicit HistorySignInStateWatcherTestBase(bool replace_sync_with_signin) {
+    feature_list_.InitWithFeatureState(
+        syncer::kReplaceSyncPromosWithSignInPromos, replace_sync_with_signin);
+    // Start with no signed-in user (this makes the TestSyncService consistent
+    // with the IdentityTestEnvironment).
+    sync_service_.SetSignedOut();
+  }
+
+ protected:
+  base::test::ScopedFeatureList feature_list_;
+  base::test::TaskEnvironment task_environment_;
+  signin::IdentityTestEnvironment identity_test_env_;
+  syncer::TestSyncService sync_service_;
+};
+
+class HistorySignInStateWatcherTest : public HistorySignInStateWatcherTestBase,
+                                      public testing::WithParamInterface<bool> {
+ public:
+  HistorySignInStateWatcherTest()
+      : HistorySignInStateWatcherTestBase(
+            /*replace_sync_with_signin=*/GetParam()) {}
+};
+
+TEST_P(HistorySignInStateWatcherTest, SignedOut) {
+  // Initially, user is signed out and sync is off.
+  ASSERT_FALSE(identity_test_env_.identity_manager()->HasPrimaryAccount(
+      signin::ConsentLevel::kSignin));
+  ASSERT_FALSE(sync_service_.IsSyncFeatureEnabled());
+
+  StrictMock<base::MockCallback<base::RepeatingClosure>> callback;
+  HistorySignInStateWatcher watcher(identity_test_env_.identity_manager(),
+                                    &sync_service_, callback.Get());
+
+  EXPECT_EQ(HistorySignInState::kSignedOut, watcher.GetSignInState());
+}
+
+TEST_P(HistorySignInStateWatcherTest, NullServices) {
+  StrictMock<base::MockCallback<base::RepeatingClosure>> callback;
+  HistorySignInStateWatcher watcher(nullptr, nullptr, callback.Get());
+
+  EXPECT_EQ(HistorySignInState::kSignedOut, watcher.GetSignInState());
+}
+
+class HistorySignInStateWatcherSyncToSigninTest
+    : public HistorySignInStateWatcherTestBase {
+ public:
+  HistorySignInStateWatcherSyncToSigninTest()
+      : HistorySignInStateWatcherTestBase(/*replace_sync_with_signin=*/true) {}
+};
+
+TEST_F(HistorySignInStateWatcherSyncToSigninTest, NotifiesAboutStateChanges) {
+  StrictMock<base::MockCallback<base::RepeatingClosure>> callback;
+  HistorySignInStateWatcher watcher(identity_test_env_.identity_manager(),
+                                    &sync_service_, callback.Get());
+  ASSERT_EQ(HistorySignInState::kSignedOut, watcher.GetSignInState());
+
+  // Signing in, but without history, should not change the state, nor trigger a
+  // notification yet.
+  CoreAccountInfo account_info = identity_test_env_.MakePrimaryAccountAvailable(
+      "test@example.com", signin::ConsentLevel::kSignin);
+  sync_service_.SetSignedIn(signin::ConsentLevel::kSignin, account_info);
+  sync_service_.GetUserSettings()->SetSelectedType(
+      syncer::UserSelectableType::kHistory, false);
+  sync_service_.FireStateChanged();
+  EXPECT_EQ(HistorySignInState::kSignedOut, watcher.GetSignInState());
+
+  // Opting in to history should change the state and trigger a notification.
+  sync_service_.GetUserSettings()->SetSelectedType(
+      syncer::UserSelectableType::kHistory, true);
+  EXPECT_CALL(callback, Run());
+  sync_service_.FireStateChanged();
+  EXPECT_EQ(HistorySignInState::kSignedIn, watcher.GetSignInState());
+
+#if !BUILDFLAG(IS_CHROMEOS)
+  // Signing out again should once again change the state and trigger a
+  // notification.
+  identity_test_env_.ClearPrimaryAccount();
+  sync_service_.SetSignedOut();
+  EXPECT_CALL(callback, Run());
+  sync_service_.FireStateChanged();
+  EXPECT_EQ(HistorySignInState::kSignedOut, watcher.GetSignInState());
+#endif  // BUILDFLAG(IS_CHROMEOS)
+}
+
+class HistorySignInStateWatcherWithoutSyncToSigninTest
+    : public HistorySignInStateWatcherTestBase {
+ public:
+  HistorySignInStateWatcherWithoutSyncToSigninTest()
+      : HistorySignInStateWatcherTestBase(/*replace_sync_with_signin=*/false) {}
+};
+
+TEST_F(HistorySignInStateWatcherWithoutSyncToSigninTest,
+       NotifiesAboutStateChanges) {
+  StrictMock<base::MockCallback<base::RepeatingClosure>> callback;
+  HistorySignInStateWatcher watcher(identity_test_env_.identity_manager(),
+                                    &sync_service_, callback.Get());
+  ASSERT_EQ(HistorySignInState::kSignedOut, watcher.GetSignInState());
+
+  // Just signing in (without enabling Sync) should *not* change the state, nor
+  // trigger a notification.
+  CoreAccountInfo account_info = identity_test_env_.MakePrimaryAccountAvailable(
+      "test@example.com", signin::ConsentLevel::kSignin);
+  sync_service_.SetSignedIn(signin::ConsentLevel::kSignin, account_info);
+  sync_service_.FireStateChanged();
+  EXPECT_EQ(HistorySignInState::kSignedOut, watcher.GetSignInState());
+
+  // Enabling Sync should change the state and trigger a notification.
+  account_info = identity_test_env_.MakePrimaryAccountAvailable(
+      "test@example.com", signin::ConsentLevel::kSync);
+  sync_service_.SetSignedIn(signin::ConsentLevel::kSync, account_info);
+  EXPECT_CALL(callback, Run());
+  sync_service_.FireStateChanged();
+  EXPECT_EQ(HistorySignInState::kSignedIn, watcher.GetSignInState());
+
+#if !BUILDFLAG(IS_CHROMEOS)
+  // Signing out and disabling Sync again should once again change the state and
+  // trigger a notification.
+  sync_service_.SetSignedOut();
+  identity_test_env_.ClearPrimaryAccount();
+  EXPECT_CALL(callback, Run());
+  sync_service_.FireStateChanged();
+  EXPECT_EQ(HistorySignInState::kSignedOut, watcher.GetSignInState());
+#endif  // BUILDFLAG(IS_CHROMEOS)
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+                         HistorySignInStateWatcherTest,
+                         testing::Bool(),
+                         [](const testing::TestParamInfo<bool>& info) {
+                           return info.param ? "WithSyncToSignin"
+                                             : "WithoutSyncToSignin";
+                         });
+
+}  // namespace
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 43a591785..497aa71 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -8193,6 +8193,7 @@
       "../browser/ui/webui/flags/flags_ui_handler_unittest.cc",
       "../browser/ui/webui/history/browsing_history_handler_unittest.cc",
       "../browser/ui/webui/history/foreign_session_handler_unittest.cc",
+      "../browser/ui/webui/history/history_sign_in_state_watcher_unittest.cc",
       "../browser/ui/webui/managed_ui_handler_unittest.cc",
       "../browser/ui/webui/metrics_reporter/metrics_reporter_unittest.cc",
       "../browser/ui/webui/metrics_reporter/mock_metrics_reporter.cc",
diff --git a/chromeos/ash/components/network/onc/onc_certificate_importer.h b/chromeos/ash/components/network/onc/onc_certificate_importer.h
index 59fcde9..da65fe6 100644
--- a/chromeos/ash/components/network/onc/onc_certificate_importer.h
+++ b/chromeos/ash/components/network/onc/onc_certificate_importer.h
@@ -28,23 +28,6 @@
 
   virtual ~CertificateImporter() {}
 
-  // This is intended for user-initiated ONC imports.
-  // Permanently imports server, authority and client certificates from
-  // |certificates|. Certificates will be given web trust if requested.
-  // If the "Remove" field of a certificate is enabled, then removes the
-  // certificate from the store instead of importing.
-  // When the import is completed, |done_callback| will be called with |success|
-  // equal to true if all certificates were imported successfully.
-  // Never calls |done_callback| after this importer is destructed.
-  virtual void ImportAllCertificatesUserInitiated(
-      const std::vector<
-          chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate>&
-          server_or_authority_certificates,
-      const std::vector<
-          chromeos::onc::OncParsedCertificates::ClientCertificate>&
-          client_certificates,
-      DoneCallback done_callback) = 0;
-
   // Permanently imports the client certificates given by |client_certificates|.
   // When the import is completed, |done_callback| will be called with |success|
   // equal to true if all certificates were imported successfully.
diff --git a/chromeos/ash/components/network/onc/onc_certificate_importer_impl.cc b/chromeos/ash/components/network/onc/onc_certificate_importer_impl.cc
index b05b46736..b9c7dec 100644
--- a/chromeos/ash/components/network/onc/onc_certificate_importer_impl.cc
+++ b/chromeos/ash/components/network/onc/onc_certificate_importer_impl.cc
@@ -36,23 +36,6 @@
 
 CertificateImporterImpl::~CertificateImporterImpl() = default;
 
-void CertificateImporterImpl::ImportAllCertificatesUserInitiated(
-    const std::vector<
-        chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate>&
-        server_or_authority_certificates,
-    const std::vector<chromeos::onc::OncParsedCertificates::ClientCertificate>&
-        client_certificates,
-    DoneCallback done_callback) {
-  VLOG(2) << "Importing " << server_or_authority_certificates.size()
-          << " server/authority certificates and " << client_certificates.size()
-          << " client certificates";
-  RunTaskOnIOTaskRunnerAndCallDoneCallback(
-      base::BindOnce(&StoreAllCertificatesUserInitiated,
-                     server_or_authority_certificates, client_certificates,
-                     target_nssdb_),
-      std::move(done_callback));
-}
-
 void CertificateImporterImpl::ImportClientCertificates(
     const std::vector<chromeos::onc::OncParsedCertificates::ClientCertificate>&
         client_certificates,
diff --git a/chromeos/ash/components/network/onc/onc_certificate_importer_impl.h b/chromeos/ash/components/network/onc/onc_certificate_importer_impl.h
index 102f5ae3..9cd289d 100644
--- a/chromeos/ash/components/network/onc/onc_certificate_importer_impl.h
+++ b/chromeos/ash/components/network/onc/onc_certificate_importer_impl.h
@@ -48,15 +48,6 @@
   ~CertificateImporterImpl() override;
 
   // CertificateImporter overrides
-  void ImportAllCertificatesUserInitiated(
-      const std::vector<
-          chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate>&
-          server_or_authority_certificates,
-      const std::vector<
-          chromeos::onc::OncParsedCertificates::ClientCertificate>&
-          client_certificates,
-      DoneCallback done_callback) override;
-
   void ImportClientCertificates(
       const std::vector<
           chromeos::onc::OncParsedCertificates::ClientCertificate>&
diff --git a/chromeos/ash/components/network/onc/onc_certificate_importer_impl_unittest.cc b/chromeos/ash/components/network/onc/onc_certificate_importer_impl_unittest.cc
index 2a01355b..ba450b4 100644
--- a/chromeos/ash/components/network/onc/onc_certificate_importer_impl_unittest.cc
+++ b/chromeos/ash/components/network/onc/onc_certificate_importer_impl_unittest.cc
@@ -65,14 +65,11 @@
   }
 
   // Runs the import on the certificates specified in |filename|.
-  // |import_type| specifies if only client certificates should be imported, or
-  // if all certificates should be imported.
   // |expected_parse_success| should be true if at least one certificate in
   // |filename| is expected to have parse errors.
   // |expected_import_success| is the expected result of importing the
   // certificates which did not have parsing errors.
   void AddCertificatesFromFile(const std::string& filename,
-                               ImportType import_type,
                                bool expected_parse_success,
                                bool expected_import_success) {
     base::Value::Dict onc =
@@ -86,23 +83,10 @@
         std::make_unique<chromeos::onc::OncParsedCertificates>(
             onc_certificates_);
     EXPECT_EQ(expected_parse_success, !onc_parsed_certificates->has_error());
-    switch (import_type) {
-      case ImportType::kClientCertificatesOnly:
-        importer.ImportClientCertificates(
-            onc_parsed_certificates->client_certificates(),
-            base::BindOnce(&ONCCertificateImporterImplTest::OnImportCompleted,
-                           base::Unretained(this), expected_import_success));
-        break;
-      case ImportType::kAllCertificates:
-        importer.ImportAllCertificatesUserInitiated(
-            onc_parsed_certificates->server_or_authority_certificates(),
-            onc_parsed_certificates->client_certificates(),
-            base::BindOnce(&ONCCertificateImporterImplTest::OnImportCompleted,
-                           base::Unretained(this), expected_import_success));
-        break;
-      default:
-        NOTREACHED();
-    }
+    importer.ImportClientCertificates(
+        onc_parsed_certificates->client_certificates(),
+        base::BindOnce(&ONCCertificateImporterImplTest::OnImportCompleted,
+                       base::Unretained(this), expected_import_success));
 
     task_runner_->RunUntilIdle();
 
@@ -111,15 +95,13 @@
   }
 
   void AddCertificateFromFile(const std::string& filename,
-                              ImportType import_type,
                               net::CertType expected_type,
                               std::string* guid) {
     std::string guid_temporary;
     if (!guid)
       guid = &guid_temporary;
 
-    AddCertificatesFromFile(filename, import_type,
-                            true /* expected_parse_success */,
+    AddCertificatesFromFile(filename, true /* expected_parse_success */,
                             true /* expected_import_success */);
 
     if (expected_type == net::SERVER_CERT || expected_type == net::CA_CERT) {
@@ -184,39 +166,22 @@
   }
 };
 
-TEST_F(ONCCertificateImporterImplTest, MultipleCertificates) {
-  AddCertificatesFromFile("managed_toplevel2.onc", ImportType::kAllCertificates,
-                          true /* expected_parse_success */,
-                          true /* expected_import_success */);
-  EXPECT_EQ(onc_certificates_.size(), public_list_.size());
-  EXPECT_TRUE(private_list_.empty());
-  EXPECT_EQ(2ul, public_list_.size());
-}
 
 TEST_F(ONCCertificateImporterImplTest, OnlyClientCertificatesImpored) {
-  AddCertificatesFromFile(
-      "managed_toplevel2.onc", ImportType::kClientCertificatesOnly,
-      true /* expected_parse_success */, true /* expected_import_success */);
-  AddCertificatesFromFile(
-      "certificate-client.onc", ImportType::kClientCertificatesOnly,
-      true /* expected_parse_success */, true /* expected_import_success */);
+  AddCertificatesFromFile("managed_toplevel2.onc",
+                          true /* expected_parse_success */,
+                          true /* expected_import_success */);
+  AddCertificatesFromFile("certificate-client.onc",
+                          true /* expected_parse_success */,
+                          true /* expected_import_success */);
   EXPECT_EQ(0ul, public_list_.size());
   EXPECT_EQ(1ul, private_list_.size());
 }
 
-TEST_F(ONCCertificateImporterImplTest, MultipleCertificatesWithFailures) {
-  AddCertificatesFromFile(
-      "toplevel_partially_invalid.onc", ImportType::kAllCertificates,
-      false /* expected_parse_success */, true /* expected_import_success */);
-  EXPECT_EQ(3ul, onc_certificates_.size());
-  EXPECT_EQ(1ul, private_list_.size());
-  EXPECT_TRUE(public_list_.empty());
-}
 
 TEST_F(ONCCertificateImporterImplTest, AddClientCertificate) {
   std::string guid;
-  AddCertificateFromFile("certificate-client.onc", ImportType::kAllCertificates,
-                         net::USER_CERT, &guid);
+  AddCertificateFromFile("certificate-client.onc", net::USER_CERT, &guid);
   EXPECT_EQ(1ul, private_list_.size());
   EXPECT_TRUE(public_list_.empty());
 
@@ -252,107 +217,28 @@
   }
 }
 
-TEST_F(ONCCertificateImporterImplTest, AddServerCertificateWithWebTrust) {
-  AddCertificateFromFile("certificate-server.onc", ImportType::kAllCertificates,
-                         net::SERVER_CERT, NULL);
-
-  SECKEYPrivateKeyList* privkey_list =
-      PK11_ListPrivKeysInSlot(private_nssdb_.slot(), NULL, NULL);
-  EXPECT_FALSE(privkey_list);
-
-  SECKEYPublicKeyList* pubkey_list =
-      PK11_ListPublicKeysInSlot(private_nssdb_.slot(), NULL);
-  EXPECT_FALSE(pubkey_list);
-
-  ASSERT_EQ(1u, public_list_.size());
-  EXPECT_TRUE(private_list_.empty());
-}
-
-TEST_F(ONCCertificateImporterImplTest, AddWebAuthorityCertificateWithWebTrust) {
-  AddCertificateFromFile("certificate-web-authority.onc",
-                         ImportType::kAllCertificates, net::CA_CERT, NULL);
-
-  SECKEYPrivateKeyList* privkey_list =
-      PK11_ListPrivKeysInSlot(private_nssdb_.slot(), NULL, NULL);
-  EXPECT_FALSE(privkey_list);
-
-  SECKEYPublicKeyList* pubkey_list =
-      PK11_ListPublicKeysInSlot(private_nssdb_.slot(), NULL);
-  EXPECT_FALSE(pubkey_list);
-
-  ASSERT_EQ(1u, public_list_.size());
-  EXPECT_TRUE(private_list_.empty());
-}
-
-TEST_F(ONCCertificateImporterImplTest, AddAuthorityCertificateWithoutWebTrust) {
-  AddCertificateFromFile("certificate-authority.onc",
-                         ImportType::kAllCertificates, net::CA_CERT, NULL);
-  SECKEYPrivateKeyList* privkey_list =
-      PK11_ListPrivKeysInSlot(private_nssdb_.slot(), NULL, NULL);
-  EXPECT_FALSE(privkey_list);
-
-  SECKEYPublicKeyList* pubkey_list =
-      PK11_ListPublicKeysInSlot(private_nssdb_.slot(), NULL);
-  EXPECT_FALSE(pubkey_list);
-}
-
-struct CertParam {
-  CertParam(net::CertType certificate_type,
-            const char* original_filename,
-            const char* update_filename)
-      : cert_type(certificate_type),
-        original_file(original_filename),
-        update_file(update_filename) {}
-
-  net::CertType cert_type;
-  const char* original_file;
-  const char* update_file;
-};
-
-class ONCCertificateImporterImplTestWithParam :
-      public ONCCertificateImporterImplTest,
-      public testing::WithParamInterface<CertParam> {
-};
-
-TEST_P(ONCCertificateImporterImplTestWithParam, UpdateCertificate) {
+TEST_F(ONCCertificateImporterImplTest, UpdateCertificate) {
   // First we import a certificate.
   {
     SCOPED_TRACE("Import original certificate");
-    AddCertificateFromFile(GetParam().original_file,
-                           ImportType::kAllCertificates, GetParam().cert_type,
-                           NULL);
+    AddCertificateFromFile("certificate-client.onc", net::USER_CERT, NULL);
   }
 
   // Now we import the same certificate with a different GUID. In case of a
   // client cert, the cert should be retrievable via the new GUID.
   {
     SCOPED_TRACE("Import updated certificate");
-    AddCertificateFromFile(GetParam().update_file, ImportType::kAllCertificates,
-                           GetParam().cert_type, NULL);
-  }
-}
-
-TEST_P(ONCCertificateImporterImplTestWithParam, ReimportCertificate) {
-  // Verify that reimporting a client certificate works.
-  for (int i = 0; i < 2; ++i) {
-    SCOPED_TRACE("Import certificate, iteration " + base::NumberToString(i));
-    AddCertificateFromFile(GetParam().original_file,
-                           ImportType::kAllCertificates, GetParam().cert_type,
+    AddCertificateFromFile("certificate-client-update.onc", net::USER_CERT,
                            NULL);
   }
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ONCCertificateImporterImplTestWithParam,
-    ONCCertificateImporterImplTestWithParam,
-    ::testing::Values(CertParam(net::USER_CERT,
-                                "certificate-client.onc",
-                                "certificate-client-update.onc"),
-                      CertParam(net::SERVER_CERT,
-                                "certificate-server.onc",
-                                "certificate-server-update.onc"),
-                      CertParam(net::CA_CERT,
-                                "certificate-web-authority.onc",
-                                "certificate-web-authority-update.onc")));
+TEST_F(ONCCertificateImporterImplTest, ReimportCertificate) {
+  // Verify that reimporting a client certificate works.
+  for (int i = 0; i < 2; ++i) {
+    SCOPED_TRACE("Import certificate, iteration " + base::NumberToString(i));
+    AddCertificateFromFile("certificate-client.onc", net::USER_CERT, NULL);
+  }
+}
 
 }  // namespace ash::onc
diff --git a/clank b/clank
index 722cdc7..2f030b8 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 722cdc7d46bd7c87d9b93b991d5ae1cc55205a0e
+Subproject commit 2f030b8b2858ba5b64842bf5a6268933929fddec
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index f86c8f7..9ed7be1a 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -542,7 +542,7 @@
 // TODO(crbug.com/324199622) When abandoned, remove FormFieldData::is_visible.
 BASE_FEATURE(kAutofillDetectFieldVisibility,
              "AutofillDetectFieldVisibility",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // If enabled, new heuristics are applied for disambiguating multiple possible
 // types in a form field. Otherwise, only the already established heuristic for
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingsResources.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingsResources.java
index 897cc27..daebcd5 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingsResources.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingsResources.java
@@ -820,15 +820,25 @@
         return getResourceItem(contentType).getDefaultDisabledValue();
     }
 
+    public static int getCategorySummary(@ContentSettingValues int value, boolean isOneTime) {
+        return getCategorySummary(value, isOneTime, /* isApproximateGeolocation= */ false);
+    }
+
     /**
      * Returns the string resource id for a given ContentSetting to show with a permission category.
      *
      * @param value The ContentSetting for which we want the resource.
      * @param isOneTime Whether the content setting value has a OneTime session model.
      */
-    public static int getCategorySummary(@ContentSettingValues int value, boolean isOneTime) {
+    public static int getCategorySummary(
+            @ContentSettingValues int value, boolean isOneTime, boolean isApproximateGeolocation) {
         switch (value) {
             case ContentSettingValues.ALLOW:
+                if (isApproximateGeolocation) {
+                    return isOneTime
+                            ? R.string.website_settings_category_approx_geo_allowed_this_time
+                            : R.string.website_settings_category_approx_geo_allowed;
+                }
                 return isOneTime
                         ? R.string.website_settings_category_allowed_this_time
                         : R.string.website_settings_category_allowed;
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
index 56aa1a71..d2792b3 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -167,6 +167,8 @@
                 return "camera_permission_list";
             case ContentSettingsType.GEOLOCATION:
                 return "location_access_list";
+            case ContentSettingsType.GEOLOCATION_WITH_OPTIONS:
+                return "location_with_options_access_list";
             case ContentSettingsType.HAND_TRACKING:
                 return "hand_tracking_permission_list";
             case ContentSettingsType.MEDIASTREAM_MIC:
@@ -253,6 +255,10 @@
     // Maximum value used for the order of the permissions
     private int mMaxPermissionOrder;
 
+    // Stores whether the location permission was initially approximate to ensure we toggle between
+    // permissions consistently.
+    private boolean mHasApproximateLocationGrant;
+
     private final ObservableSupplierImpl<String> mPageTitle = new ObservableSupplierImpl<>();
 
     private class SingleWebsitePermissionsPopulator
@@ -608,6 +614,8 @@
                 setUpJavascriptPreference(preference);
             } else if (type == ContentSettingsType.GEOLOCATION) {
                 setUpLocationPreference(preference);
+            } else if (type == ContentSettingsType.GEOLOCATION_WITH_OPTIONS) {
+                setUpLocationWithOptionsPreference(preference);
             } else if (type == ContentSettingsType.NOTIFICATIONS) {
                 setUpNotificationsPreference(preference, mSite.isEmbargoed(type));
             } else if (type == ContentSettingsType.AUTO_PICTURE_IN_PICTURE) {
@@ -618,8 +626,7 @@
             } else {
                 setupContentSettingsPreference(
                         preference,
-                        mSite.getContentSetting(
-                                getSiteSettingsDelegate().getBrowserContextHandle(), type),
+                        mSite.getContentSetting(getBrowserContextHandle(), type),
                         mSite.isEmbargoed(type),
                         isOneTime(type));
             }
@@ -640,8 +647,7 @@
             Context context = preference.getContext();
             preference.setTitle(SiteSettingsUtil.generateStorageUsageText(context, usage, cookies));
             preference.setDataForDisplay(mSite.getTitle(), appFound, /* isGroup= */ false);
-            if (mSite.isCookieDeletionDisabled(
-                    getSiteSettingsDelegate().getBrowserContextHandle())) {
+            if (mSite.isCookieDeletionDisabled(getBrowserContextHandle())) {
                 preference.setEnabled(false);
             }
         } else {
@@ -658,7 +664,7 @@
                         : R.string.website_reset_full);
         preference.setOrder(mMaxPermissionOrder + 1);
         preference.setOnPreferenceClickListener(this);
-        if (mSite.isCookieDeletionDisabled(getSiteSettingsDelegate().getBrowserContextHandle())) {
+        if (mSite.isCookieDeletionDisabled(getBrowserContextHandle())) {
             preference.setEnabled(false);
         }
     }
@@ -746,8 +752,7 @@
     private void setUpNotificationsPreference(Preference preference, boolean isEmbargoed) {
         @ContentSettingsType.EnumType int notificationType = ContentSettingsType.NOTIFICATIONS;
         final @ContentSettingValues @Nullable Integer value =
-                mSite.getContentSetting(
-                        getSiteSettingsDelegate().getBrowserContextHandle(), notificationType);
+                mSite.getContentSetting(getBrowserContextHandle(), notificationType);
         if (setupAppDelegatePreference(
                 preference, R.string.website_notification_settings, notificationType, value)) {
             return;
@@ -801,7 +806,7 @@
         // just-in-time if the user tries to change to setting.
         if (assumeNonNull(mSite).isEmbargoed(ContentSettingsType.NOTIFICATIONS)) {
             mSite.setContentSetting(
-                    getSiteSettingsDelegate().getBrowserContextHandle(),
+                    getBrowserContextHandle(),
                     ContentSettingsType.NOTIFICATIONS,
                     ContentSettingValues.BLOCK);
         }
@@ -826,8 +831,7 @@
         // Store current value of permission to allow comparison against new value at return.
         mPreviousNotificationPermission =
                 mSite.getContentSetting(
-                        getSiteSettingsDelegate().getBrowserContextHandle(),
-                        ContentSettingsType.NOTIFICATIONS);
+                        getBrowserContextHandle(), ContentSettingsType.NOTIFICATIONS);
 
         Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
         intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId);
@@ -852,8 +856,7 @@
             @ContentSettingValues
             Integer newPermission =
                     mSite.getContentSetting(
-                            getSiteSettingsDelegate().getBrowserContextHandle(),
-                            ContentSettingsType.NOTIFICATIONS);
+                            getBrowserContextHandle(), ContentSettingsType.NOTIFICATIONS);
             assumeNonNull(newPermission);
             // User has navigated back from system channel settings on O+. Ensure notification
             // preference is up to date, since they might have toggled it from channel settings.
@@ -873,7 +876,7 @@
                     && newPermission != ContentSettingValues.ALLOW) {
                 org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridgeJni.get()
                         .reportNotificationRevokedForOrigin(
-                                getSiteSettingsDelegate().getBrowserContextHandle(),
+                                getBrowserContextHandle(),
                                 mSite.getAddress().getOrigin(),
                                 newPermission);
                 mPreviousNotificationPermission = null;
@@ -903,7 +906,7 @@
                     R.drawable.ic_delete_white_24dp,
                     R.string.website_settings_revoke_device_permission,
                     (View view) -> {
-                        info.revoke(getSiteSettingsDelegate().getBrowserContextHandle());
+                        info.revoke(getBrowserContextHandle());
                         preferenceScreen.removePreference(preference);
                         mChooserPermissionPreferences.remove(preference);
 
@@ -941,7 +944,7 @@
     @RequiresNonNull({"mSite"})
     private void setUpEmbeddedContentSettingPreferences() {
         PreferenceScreen preferenceScreen = getPreferenceScreen();
-        BrowserContextHandle handle = getSiteSettingsDelegate().getBrowserContextHandle();
+        BrowserContextHandle handle = getBrowserContextHandle();
 
         for (List<ContentSettingException> entries : mSite.getEmbeddedPermissions().values()) {
             for (ContentSettingException info : entries) {
@@ -1094,8 +1097,7 @@
         boolean adBlockingActivated =
                 SiteSettingsCategory.adsCategoryEnabled()
                         && WebsitePreferenceBridge.getAdBlockingActivated(
-                                getSiteSettingsDelegate().getBrowserContextHandle(),
-                                mSite.getAddress().getOrigin())
+                                getBrowserContextHandle(), mSite.getAddress().getOrigin())
                         && findPreference(assumeNonNull(getPreferenceKey(ContentSettingsType.ADS)))
                                 != null;
 
@@ -1112,8 +1114,7 @@
         // the user to the same location. It is preferrable, however, that we give Geolocation some
         // priority because that category is the only one that potentially shows an additional
         // warning (when Location is turned off globally).
-        BrowserContextHandle browserContextHandle =
-                getSiteSettingsDelegate().getBrowserContextHandle();
+        BrowserContextHandle browserContextHandle = getBrowserContextHandle();
         if (showWarningFor(SiteSettingsCategory.Type.DEVICE_LOCATION)) {
             return SiteSettingsCategory.createFromType(
                     browserContextHandle, SiteSettingsCategory.Type.DEVICE_LOCATION);
@@ -1144,8 +1145,7 @@
 
     @RequiresNonNull({"mSite"})
     private boolean showWarningFor(@SiteSettingsCategory.Type int type) {
-        BrowserContextHandle browserContextHandle =
-                getSiteSettingsDelegate().getBrowserContextHandle();
+        BrowserContextHandle browserContextHandle = getBrowserContextHandle();
 
         var content_settings_type = SiteSettingsCategory.contentSettingsType(type);
 
@@ -1191,6 +1191,7 @@
         return false;
     }
 
+    @RequiresNonNull({"mSite"})
     private void setupContentSettingsPreference(
             Preference preference,
             @ContentSettingValues @Nullable Integer value,
@@ -1201,19 +1202,34 @@
         preference.setOnPreferenceChangeListener(this);
         @ContentSettingsType.EnumType
         int contentType = getContentSettingsTypeFromPreferenceKey(preference.getKey());
+        boolean isApproximateGeolocation =
+                contentType == ContentSettingsType.GEOLOCATION_WITH_OPTIONS
+                        && mHasApproximateLocationGrant;
         preference.setSummary(
                 isEmbargoed
                         ? getString(R.string.automatically_blocked)
-                        : getString(ContentSettingsResources.getCategorySummary(value, isOneTime)));
+                        : getString(
+                                ContentSettingsResources.getCategorySummary(
+                                        value, isOneTime, isApproximateGeolocation)));
         if (preference instanceof ChromeImageViewPreference) {
             ChromeImageViewPreference oneTimePreference = (ChromeImageViewPreference) preference;
             oneTimePreference.setImageView(
                     R.drawable.material_ic_close_24dp,
                     R.string.website_settings_revoke_permission,
                     (View view) -> {
-                        // TODO(crbug.com/418941286): Revoke the permission by calling
-                        // onPreferenceChanged() with the new value.
+                        assumeNonNull(mSite);
+                        PermissionInfo permissionInfo =
+                                assumeNonNull(mSite.getPermissionInfo(contentType));
+                        if (contentType == ContentSettingsType.GEOLOCATION_WITH_OPTIONS) {
+                            permissionInfo.setGeolocationSetting(getBrowserContextHandle(), null);
+                        } else {
+                            permissionInfo.setContentSetting(
+                                    getBrowserContextHandle(), ContentSettingValues.DEFAULT);
+                        }
                         getPreferenceScreen().removePreference(oneTimePreference);
+                        if (mWebsiteSettingsObserver != null) {
+                            mWebsiteSettingsObserver.onPermissionChanged();
+                        }
                     });
             if (contentType == mHighlightedPermission) {
                 oneTimePreference.setBackgroundColor(mHighlightColor);
@@ -1249,7 +1265,7 @@
 
         SiteSettingsCategory category =
                 SiteSettingsCategory.createFromContentSettingsType(
-                        getSiteSettingsDelegate().getBrowserContextHandle(), contentType);
+                        getBrowserContextHandle(), contentType);
         if (category != null
                 && value != null
                 && value != ContentSettingValues.BLOCK
@@ -1269,11 +1285,13 @@
 
     @RequiresNonNull({"mSite"})
     private void setUpLocationPreference(Preference preference) {
+        if (PermissionsAndroidFeatureMap.isEnabled(
+                PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_PERMISSION)) {
+            return;
+        }
         @ContentSettingValues
         @Nullable Integer permission =
-                mSite.getContentSetting(
-                        getSiteSettingsDelegate().getBrowserContextHandle(),
-                        ContentSettingsType.GEOLOCATION);
+                mSite.getContentSetting(getBrowserContextHandle(), ContentSettingsType.GEOLOCATION);
         if (setupAppDelegatePreference(
                 preference,
                 R.string.website_location_settings,
@@ -1290,13 +1308,44 @@
     }
 
     @RequiresNonNull({"mSite"})
+    private void setUpLocationWithOptionsPreference(Preference preference) {
+        if (!PermissionsAndroidFeatureMap.isEnabled(
+                PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_PERMISSION)) {
+            return;
+        }
+        var info = mSite.getPermissionInfo(ContentSettingsType.GEOLOCATION_WITH_OPTIONS);
+        if (info == null) {
+            return;
+        }
+        GeolocationSetting permission = info.getGeolocationSetting(getBrowserContextHandle());
+
+        if (permission.mApproximate == ContentSettingValues.ALLOW
+                && permission.mApproximate != permission.mPrecise) {
+            mHasApproximateLocationGrant = true;
+        }
+
+        if (setupAppDelegatePreference(
+                preference,
+                R.string.website_location_settings,
+                ContentSettingsType.GEOLOCATION_WITH_OPTIONS,
+                permission.mApproximate)) {
+            return;
+        }
+
+        setupContentSettingsPreference(
+                preference,
+                permission.mApproximate,
+                mSite.isEmbargoed(ContentSettingsType.GEOLOCATION_WITH_OPTIONS),
+                isOneTime(ContentSettingsType.GEOLOCATION_WITH_OPTIONS));
+    }
+
+    @RequiresNonNull({"mSite"})
     private void setUpSoundPreference(Preference preference) {
         if (!getArguments().getBoolean(EXTRA_SHOW_SOUND, true)) {
             return;
         }
 
-        BrowserContextHandle browserContextHandle =
-                getSiteSettingsDelegate().getBrowserContextHandle();
+        BrowserContextHandle browserContextHandle = getBrowserContextHandle();
         @ContentSettingValues
         @Nullable Integer currentValue =
                 mSite.getContentSetting(browserContextHandle, ContentSettingsType.SOUND);
@@ -1327,8 +1376,7 @@
             return;
         }
 
-        BrowserContextHandle browserContextHandle =
-                getSiteSettingsDelegate().getBrowserContextHandle();
+        BrowserContextHandle browserContextHandle = getBrowserContextHandle();
         @ContentSettingValues
         @Nullable Integer currentValue =
                 mSite.getContentSetting(
@@ -1355,8 +1403,7 @@
 
     @RequiresNonNull({"mSite"})
     private void setUpJavascriptPreference(Preference preference) {
-        BrowserContextHandle browserContextHandle =
-                getSiteSettingsDelegate().getBrowserContextHandle();
+        BrowserContextHandle browserContextHandle = getBrowserContextHandle();
         @ContentSettingValues
         @Nullable Integer currentValue =
                 mSite.getContentSetting(browserContextHandle, ContentSettingsType.JAVASCRIPT);
@@ -1377,15 +1424,13 @@
 
     /**
      * Updates the ads list preference based on whether the site is a candidate for blocking. This
-     * has some custom behavior.
-     * 1. If the site is a candidate and has activation, the permission should show up even if it
-     *    is set as the default (e.g. |preference| is null).
-     * 2. The BLOCK string is custom.
+     * has some custom behavior. 1. If the site is a candidate and has activation, the permission
+     * should show up even if it is set as the default (e.g. |preference| is null). 2. The BLOCK
+     * string is custom.
      */
     @RequiresNonNull({"mSite"})
     private void setUpAdsPreference(Preference preference) {
-        BrowserContextHandle browserContextHandle =
-                getSiteSettingsDelegate().getBrowserContextHandle();
+        BrowserContextHandle browserContextHandle = getBrowserContextHandle();
         // Do not show the setting if the category is not enabled.
         if (!SiteSettingsCategory.adsCategoryEnabled()) {
             setupContentSettingsPreference(
@@ -1471,8 +1516,9 @@
         // It is possible that this UI is destroyed while a dialog is open because
         // incognito mode is closed through the system notification.
         if (getView() == null) return true;
-        BrowserContextHandle browserContextHandle =
-                getSiteSettingsDelegate().getBrowserContextHandle();
+        assumeNonNull(mSite);
+
+        BrowserContextHandle browserContextHandle = getBrowserContextHandle();
         int type = getContentSettingsTypeFromPreferenceKey(preference.getKey());
         if (type == ContentSettingsType.DEFAULT) return false;
 
@@ -1483,11 +1529,29 @@
             permission = (Integer) newValue;
         }
 
-        assumeNonNull(mSite).setContentSetting(browserContextHandle, type, permission);
+        if (type == ContentSettingsType.GEOLOCATION_WITH_OPTIONS) {
+            PermissionInfo permissionInfo = assumeNonNull(mSite.getPermissionInfo(type));
+            var oldSetting = permissionInfo.getGeolocationSetting(browserContextHandle);
+            var newPreciseValue = permission;
+            if (mHasApproximateLocationGrant && permission == ContentSettingValues.ALLOW) {
+                newPreciseValue = oldSetting.mPrecise;
+            }
+            permissionInfo.setGeolocationSetting(
+                    browserContextHandle,
+                    new GeolocationSetting(
+                            /* approximate= */ permission, /* precise= */ newPreciseValue));
+        } else {
+            mSite.setContentSetting(browserContextHandle, type, permission);
+        }
         // In Clank, one time grants are only possible via prompt, not via page
         // info.
         preference.setSummary(
-                getString(ContentSettingsResources.getCategorySummary(permission, false)));
+                getString(
+                        ContentSettingsResources.getCategorySummary(
+                                permission,
+                                false,
+                                type == ContentSettingsType.GEOLOCATION_WITH_OPTIONS
+                                        && mHasApproximateLocationGrant)));
         preference.setIcon(getContentSettingsIcon(type, permission));
 
         if (mWebsiteSettingsObserver != null) {
@@ -1536,8 +1600,7 @@
         boolean finishActivityImmediately =
                 assumeNonNull(mSite).getTotalUsage() == 0 && !hasManagedChooserPermissions();
 
-        SiteDataCleaner.resetPermissions(
-                getSiteSettingsDelegate().getBrowserContextHandle(), mSite);
+        SiteDataCleaner.resetPermissions(getBrowserContextHandle(), mSite);
         SiteDataCleaner.clearData(getSiteSettingsDelegate(), mSite, mDataClearedCallback);
 
         RecordHistogram.recordEnumeratedHistogram(
@@ -1604,8 +1667,7 @@
                                 R.string.reset,
                                 (dialog, which) -> {
                                     SiteDataCleaner.resetPermissions(
-                                            getSiteSettingsDelegate().getBrowserContextHandle(),
-                                            assumeNonNull(mSite));
+                                            getBrowserContextHandle(), assumeNonNull(mSite));
                                     if (mWebsiteSettingsObserver != null) {
                                         mWebsiteSettingsObserver.onPermissionsReset();
                                     }
@@ -1654,6 +1716,10 @@
         return false;
     }
 
+    private BrowserContextHandle getBrowserContextHandle() {
+        return getSiteSettingsDelegate().getBrowserContextHandle();
+    }
+
     @Override
     public @AnimationType int getAnimationType() {
         return AnimationType.PROPERTY;
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsUtil.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsUtil.java
index 70f1a8d4..2221371 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsUtil.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsUtil.java
@@ -27,6 +27,7 @@
     public static final int[] SETTINGS_ORDER = {
         ContentSettingsType.COOKIES,
         ContentSettingsType.GEOLOCATION,
+        ContentSettingsType.GEOLOCATION_WITH_OPTIONS,
         ContentSettingsType.MEDIASTREAM_CAMERA,
         ContentSettingsType.MEDIASTREAM_MIC,
         ContentSettingsType.NOTIFICATIONS,
diff --git a/components/browser_ui/strings/android/site_settings.grdp b/components/browser_ui/strings/android/site_settings.grdp
index a4ed0c6e..9cb4f2296 100644
--- a/components/browser_ui/strings/android/site_settings.grdp
+++ b/components/browser_ui/strings/android/site_settings.grdp
@@ -145,6 +145,12 @@
     <message name="IDS_WEBSITE_SETTINGS_CATEGORY_ALLOWED_THIS_TIME" desc="Summary text explaining that a permission is allowed ephemerally, e.g. JavaScript: allowed.">
     Allowed this time
   </message>
+  <message name="IDS_WEBSITE_SETTINGS_CATEGORY_APPROX_GEO_ALLOWED" desc="Summary text explaining that the approximate location permission is allowed.">
+    Allowed • Approximate
+  </message>
+  <message name="IDS_WEBSITE_SETTINGS_CATEGORY_APPROX_GEO_ALLOWED_THIS_TIME" desc="Summary text explaining that the approximate location permission is allowed ephemerally.">
+    Allowed this time • Approximate
+  </message>
   <message name="IDS_WEBSITE_SETTINGS_CATEGORY_ALLOWED_EXCEPT_THIRD_PARTY" desc="Summary text for when only third-party cookies are blocked.">
     Allowed, except third-party
   </message>
diff --git a/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_APPROX_GEO_ALLOWED.png.sha1 b/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_APPROX_GEO_ALLOWED.png.sha1
new file mode 100644
index 0000000..bf3556f
--- /dev/null
+++ b/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_APPROX_GEO_ALLOWED.png.sha1
@@ -0,0 +1 @@
+8408cf4108789f4986a550558df613b32df76599
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_APPROX_GEO_ALLOWED_THIS_TIME.png.sha1 b/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_APPROX_GEO_ALLOWED_THIS_TIME.png.sha1
new file mode 100644
index 0000000..4f9d79db
--- /dev/null
+++ b/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_APPROX_GEO_ALLOWED_THIS_TIME.png.sha1
@@ -0,0 +1 @@
+a3b3ffb47941df9378b4fa3eb6d80b6516cb2c8c
\ No newline at end of file
diff --git a/components/history/core/browser/web_history_service.cc b/components/history/core/browser/web_history_service.cc
index 16982a5a1..ace729f 100644
--- a/components/history/core/browser/web_history_service.cc
+++ b/components/history/core/browser/web_history_service.cc
@@ -42,8 +42,6 @@
 
 namespace {
 
-const char kHistoryOAuthScope[] = "https://www.googleapis.com/auth/chromesync";
-
 const char kHistoryQueryHistoryUrl[] =
     "https://history.google.com/history/api/lookup?client=chrome";
 
@@ -160,9 +158,6 @@
 
   // Tells the request to do its thang.
   void Start() override {
-    signin::ScopeSet oauth_scopes;
-    oauth_scopes.insert(kHistoryOAuthScope);
-
     // TODO(crbug.com/40066882): Simplify this once
     // kReplaceSyncPromosWithSignInPromos has rolled out on all platforms.
     signin::ConsentLevel consent_level = signin::ConsentLevel::kSync;
@@ -173,7 +168,7 @@
 
     access_token_fetcher_ =
         std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
-            "web_history", identity_manager_, oauth_scopes,
+            signin::OAuthConsumerId::kWebHistoryService, identity_manager_,
             base::BindOnce(&RequestImpl::OnAccessTokenFetchComplete,
                            base::Unretained(this)),
             signin::PrimaryAccountAccessTokenFetcher::Mode::kImmediate,
@@ -193,11 +188,9 @@
     // If the response code indicates that the token might not be valid,
     // invalidate the token and try again.
     if (response_code_ == net::HTTP_UNAUTHORIZED && ++auth_retry_count_ <= 1) {
-      signin::ScopeSet oauth_scopes;
-      oauth_scopes.insert(kHistoryOAuthScope);
       identity_manager_->RemoveAccessTokenFromCache(
           identity_manager_->GetPrimaryAccountId(signin::ConsentLevel::kSignin),
-          oauth_scopes, access_token_);
+          signin::OAuthConsumerId::kWebHistoryService, access_token_);
 
       access_token_.clear();
       Start();
diff --git a/components/omnibox/browser/document_suggestions_service.cc b/components/omnibox/browser/document_suggestions_service.cc
index 9eabe74..5dd253f 100644
--- a/components/omnibox/browser/document_suggestions_service.cc
+++ b/components/omnibox/browser/document_suggestions_service.cc
@@ -156,11 +156,8 @@
 
   std::move(creation_callback).Run(request.get());
 
-  // Create and fetch an OAuth2 token.
-  signin::ScopeSet scopes;
-  scopes.insert(GaiaConstants::kCloudSearchQueryOAuth2Scope);
   token_fetcher_ = std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
-      "document_suggestions_service", identity_manager_, scopes,
+      signin::OAuthConsumerId::kDocumentSuggestionsService, identity_manager_,
       base::BindOnce(&DocumentSuggestionsService::AccessTokenAvailable,
                      base::Unretained(this), std::move(request),
                      std::move(request_body), traffic_annotation,
diff --git a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc
index 1f3a3bad..42b7818a 100644
--- a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc
+++ b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc
@@ -137,18 +137,8 @@
         }
       })");
 
-  // Create and fetch an OAuth2 token.
-  signin::ScopeSet scopes;
-
-  if (omnibox_feature_configs::SearchAggregatorProvider::Get()
-          .use_discovery_engine_oauth_scope) {
-    scopes.insert(GaiaConstants::kDiscoveryEngineCompleteQueryOAuth2Scope);
-  } else {
-    scopes.insert(GaiaConstants::kCloudSearchQueryOAuth2Scope);
-  }
   token_fetcher_ = std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
-      "enterprise_search_aggregator_suggestions_service", identity_manager_,
-      scopes,
+      signin::OAuthConsumerId::kEnterpriseSearchAggregator, identity_manager_,
       base::BindOnce(
           &EnterpriseSearchAggregatorSuggestionsService::AccessTokenAvailable,
           base::Unretained(this), std::move(requests), std::move(query),
diff --git a/components/omnibox/composebox/composebox_query_controller.cc b/components/omnibox/composebox/composebox_query_controller.cc
index 131458db..4d0a295 100644
--- a/components/omnibox/composebox/composebox_query_controller.cc
+++ b/components/omnibox/composebox/composebox_query_controller.cc
@@ -55,7 +55,6 @@
 
 constexpr char kContentTypeKey[] = "Content-Type";
 constexpr char kContentType[] = "application/x-protobuf";
-constexpr char kOAuthConsumerName[] = "ComposeboxQueryController";
 constexpr char kSessionIdQueryParameterKey[] = "gsessionid";
 
 // TODO(crbug.com/432348301): Move away from hardcoded entrypoint and lns
@@ -360,7 +359,7 @@
     signin::ScopeSet oauth_scopes;
     oauth_scopes.insert(GaiaConstants::kLensOAuth2Scope);
     return std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
-        kOAuthConsumerName, identity_manager_, oauth_scopes,
+        signin::OAuthConsumerId::kComposeboxQueryController, identity_manager_,
         std::move(token_callback),
         signin::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable,
         signin::ConsentLevel::kSignin);
diff --git a/components/password_manager/core/browser/sharing/password_sharing_recipients_downloader.cc b/components/password_manager/core/browser/sharing/password_sharing_recipients_downloader.cc
index 27255632..4ffbede 100644
--- a/components/password_manager/core/browser/sharing/password_sharing_recipients_downloader.cc
+++ b/components/password_manager/core/browser/sharing/password_sharing_recipients_downloader.cc
@@ -27,8 +27,6 @@
 
 namespace {
 
-constexpr char kPasswordSharingRecipientsOAuthConsumerName[] =
-    "PasswordSharingRecipients";
 constexpr char kPasswordSharingRecipientsEndpoint[] =
     "password_sharing_recipients";
 constexpr base::TimeDelta kRequestTimeout = base::Seconds(10);
@@ -250,8 +248,8 @@
   CHECK(!ongoing_access_token_fetch_);
   ongoing_access_token_fetch_ =
       std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
-          kPasswordSharingRecipientsOAuthConsumerName, identity_manager_,
-          signin::ScopeSet{GaiaConstants::kChromeSyncOAuth2Scope},
+          signin::OAuthConsumerId::kPasswordSharingRecipientsDownloader,
+          identity_manager_,
           base::BindOnce(
               &PasswordSharingRecipientsDownloader::AccessTokenFetched,
               base::Unretained(this)),
diff --git a/components/signin/internal/identity_manager/oauth_consumer_registry.cc b/components/signin/internal/identity_manager/oauth_consumer_registry.cc
index 2c3435f..e86b40fb 100644
--- a/components/signin/internal/identity_manager/oauth_consumer_registry.cc
+++ b/components/signin/internal/identity_manager/oauth_consumer_registry.cc
@@ -47,6 +47,14 @@
 constexpr char kPushNotificationName[] = "push_notification";
 constexpr char kKAnonymityServiceName[] = "k_anonymity_service";
 constexpr char kFeedbackUploaderName[] = "feedback_uploader";
+constexpr char kPasswordSharingRecipientsDownloaderName[] =
+    "password_sharing_recipients_downloader";
+constexpr char kWebHistoryServiceName[] = "web_history";
+constexpr char kComposeboxQueryControllerName[] = "ComposeboxQueryController";
+constexpr char kDocumentSuggestionsServiceName[] =
+    "document_suggestions_service";
+constexpr char kEnterpriseSearchAggregatorName[] =
+    "enterprise_search_aggregator";
 
 }  // namespace
 
@@ -207,6 +215,26 @@
       return OAuthConsumer(
           /*name=*/kFeedbackUploaderName,
           /*scopes=*/{GaiaConstants::kSupportContentOAuth2Scope});
+    case OAuthConsumerId::kPasswordSharingRecipientsDownloader:
+      return OAuthConsumer(
+          /*name=*/kPasswordSharingRecipientsDownloaderName,
+          /*scopes=*/{GaiaConstants::kChromeSyncOAuth2Scope});
+    case OAuthConsumerId::kWebHistoryService:
+      return OAuthConsumer(
+          /*name=*/kWebHistoryServiceName,
+          /*scopes=*/{GaiaConstants::kChromeSyncOAuth2Scope});
+    case OAuthConsumerId::kComposeboxQueryController:
+      return OAuthConsumer(
+          /*name=*/kComposeboxQueryControllerName,
+          /*scopes=*/{GaiaConstants::kLensOAuth2Scope});
+    case OAuthConsumerId::kDocumentSuggestionsService:
+      return OAuthConsumer(
+          /*name=*/kDocumentSuggestionsServiceName,
+          /*scopes=*/{GaiaConstants::kCloudSearchQueryOAuth2Scope});
+    case OAuthConsumerId::kEnterpriseSearchAggregator:
+      return OAuthConsumer(
+          /*name=*/kEnterpriseSearchAggregatorName,
+          /*scopes=*/{GaiaConstants::kDiscoveryEngineCompleteQueryOAuth2Scope});
   }
   NOTREACHED();
 }
diff --git a/components/signin/public/identity_manager/oauth_consumer_ids.h b/components/signin/public/identity_manager/oauth_consumer_ids.h
index 4280db30..8326e863 100644
--- a/components/signin/public/identity_manager/oauth_consumer_ids.h
+++ b/components/signin/public/identity_manager/oauth_consumer_ids.h
@@ -43,7 +43,12 @@
   kPushNotification = 28,
   kKAnonymityService = 29,
   kFeedbackUploader = 30,
-  kMaxValue = kFeedbackUploader,
+  kPasswordSharingRecipientsDownloader = 31,
+  kWebHistoryService = 32,
+  kComposeboxQueryController = 33,
+  kDocumentSuggestionsService = 34,
+  kEnterpriseSearchAggregator = 35,
+  kMaxValue = kEnterpriseSearchAggregator,
 };
 // LINT.ThenChange(//tools/metrics/histograms/metadata/signin/enums.xml:OAuthConsumerId)
 
diff --git a/ios/chrome/browser/providers/BUILD.gn b/ios/chrome/browser/providers/BUILD.gn
index 3962d324..6e209de 100644
--- a/ios/chrome/browser/providers/BUILD.gn
+++ b/ios/chrome/browser/providers/BUILD.gn
@@ -19,6 +19,7 @@
     "//ios/chrome/browser/providers/follow:chromium_follow",
     "//ios/chrome/browser/providers/font:chromium_font",
     "//ios/chrome/browser/providers/fullscreen:chromium_fullscreen",
+    "//ios/chrome/browser/providers/glow_effect:chromium_glow_effect",
     "//ios/chrome/browser/providers/google_one:chromium_google_one",
     "//ios/chrome/browser/providers/keyboard:chromium_keyboard",
     "//ios/chrome/browser/providers/lens:chromium_lens",
diff --git a/ios/chrome/browser/providers/glow_effect/BUILD.gn b/ios/chrome/browser/providers/glow_effect/BUILD.gn
new file mode 100644
index 0000000..fe7ce1fe
--- /dev/null
+++ b/ios/chrome/browser/providers/glow_effect/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("chromium_glow_effect") {
+  sources = [ "chromium_glow_effect.mm" ]
+  deps = [
+    "//base",
+    "//ios/public/provider/chrome/browser/glow_effect:glow_effect_api",
+  ]
+}
diff --git a/ios/chrome/browser/providers/glow_effect/chromium_glow_effect.mm b/ios/chrome/browser/providers/glow_effect/chromium_glow_effect.mm
new file mode 100644
index 0000000..79e594a
--- /dev/null
+++ b/ios/chrome/browser/providers/glow_effect/chromium_glow_effect.mm
@@ -0,0 +1,17 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/public/provider/chrome/browser/glow_effect/glow_effect_api.h"
+
+namespace ios {
+namespace provider {
+
+UIView<GlowEffect>* CreateGlowEffect(CGRect frame,
+                                     CGFloat cornerRadius,
+                                     CGFloat borderWidth) {
+  return nil;
+}
+
+}  // namespace provider
+}  // namespace ios
diff --git a/ios/public/provider/chrome/browser/glow_effect/BUILD.gn b/ios/public/provider/chrome/browser/glow_effect/BUILD.gn
new file mode 100644
index 0000000..02288bc
--- /dev/null
+++ b/ios/public/provider/chrome/browser/glow_effect/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ios/ios_sdk.gni")
+
+source_set("glow_effect_api") {
+  sources = [ "glow_effect_api.h" ]
+  deps = [ "//base" ]
+}
diff --git a/ios/public/provider/chrome/browser/glow_effect/glow_effect_api.h b/ios/public/provider/chrome/browser/glow_effect/glow_effect_api.h
new file mode 100644
index 0000000..93a422aa
--- /dev/null
+++ b/ios/public/provider/chrome/browser/glow_effect/glow_effect_api.h
@@ -0,0 +1,41 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_GLOW_EFFECT_GLOW_EFFECT_API_H_
+#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_GLOW_EFFECT_GLOW_EFFECT_API_H_
+
+#import <UIKit/UIKit.h>
+
+// Public API for the Glow Effect.
+@protocol GlowEffect <NSObject>
+
+// The duration in seconds for one full 360-degree rotation.
+@property(nonatomic, assign) CFTimeInterval rotationSpeedDuration;
+
+// The duration of the glow fade-in and fade-out animation.
+@property(nonatomic, assign) CFTimeInterval fadeAnimationDuration;
+
+// Starts the glow animation.
+- (void)startGlow;
+
+// Stops the glow animation.
+- (void)stopGlow;
+
+@end
+
+namespace ios {
+namespace provider {
+
+// Creates and returns a view that applies a glow effect on its border. `frame`
+// is optional.
+// TODO(crbug.com/440074963): This is used in a prototype, it has not been UX
+// approved yet and should not be reused for now.
+UIView<GlowEffect>* CreateGlowEffect(CGRect frame,
+                                     CGFloat cornerRadius,
+                                     CGFloat borderWidth);
+
+}  // namespace provider
+}  // namespace ios
+
+#endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_GLOW_EFFECT_GLOW_EFFECT_API_H_
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 8d70d7ed..d113012 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2220,28 +2220,6 @@
             ]
         }
     ],
-    "AutofillDetectFieldVisibility": [
-        {
-            "platforms": [
-                "android",
-                "android_webview",
-                "chromeos",
-                "chromeos_lacros",
-                "ios",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_20250523",
-                    "enable_features": [
-                        "AutofillDetectFieldVisibility"
-                    ]
-                }
-            ]
-        }
-    ],
     "AutofillEnableBuyNowPayLaterDesktop": [
         {
             "platforms": [
diff --git a/third_party/blink/renderer/core/frame/ad_tracker.cc b/third_party/blink/renderer/core/frame/ad_tracker.cc
index c7959ab68..f75b40d7c 100644
--- a/third_party/blink/renderer/core/frame/ad_tracker.cc
+++ b/third_party/blink/renderer/core/frame/ad_tracker.cc
@@ -195,8 +195,8 @@
     return;
   }
 
-  auto it = ad_script_ids_.find(probe.function->ScriptId());
-  if (it != ad_script_ids_.end() && !bottom_most_ad_script_.has_value()) {
+  auto it = ad_script_data_.find(probe.function->ScriptId());
+  if (it != ad_script_data_.end() && !bottom_most_ad_script_.has_value()) {
     bottom_most_ad_script_ = probe.function->ScriptId();
   }
 }
@@ -349,9 +349,9 @@
   // of script ids for ad frames.
   if (bottom_most_ad_script_.has_value()) {
     if (out_ad_script) {
-      auto it = ad_script_ids_.find(bottom_most_ad_script_.value());
-      if (it != ad_script_ids_.end()) {
-        *out_ad_script = it->value;
+      auto it = ad_script_data_.find(bottom_most_ad_script_.value());
+      if (it != ad_script_data_.end()) {
+        *out_ad_script = it->value.id;
       }
     }
     return true;
@@ -362,7 +362,7 @@
 
   // If we're not aware of any ad scripts at all, or any scripts in this
   // context, don't bother looking at the stack.
-  if (ad_script_ids_.empty()) {
+  if (ad_script_data_.empty()) {
     return false;
   }
   auto it = context_known_ad_scripts_.find(execution_context);
@@ -379,12 +379,12 @@
     return false;
   }
 
-  auto script_it = ad_script_ids_.find(top_script_id);
-  if (script_it != ad_script_ids_.end() && out_ad_script) {
-    *out_ad_script = script_it->value;
+  auto script_it = ad_script_data_.find(top_script_id);
+  if (script_it != ad_script_data_.end() && out_ad_script) {
+    *out_ad_script = script_it->value.id;
   }
 
-  return script_it != ad_script_ids_.end();
+  return script_it != ad_script_data_.end();
 }
 
 bool AdTracker::IsKnownAdScript(ExecutionContext* execution_context,
@@ -436,11 +436,6 @@
   auto it = context_known_ad_scripts_.find(execution_context);
   DCHECK(it != context_known_ad_scripts_.end());
 
-  AdScriptIdentifier current_ad_script = AdScriptIdentifier(
-      GetDebuggerIdForContext(v8_context), script_id, script_name);
-
-  ad_script_ids_.insert(script_id, current_ad_script);
-
   const HashMap<String, std::unique_ptr<AdProvenance>>&
       known_ad_scripts_and_provenance = it->value;
 
@@ -456,7 +451,11 @@
   // URL, and are intended to share the same provenance. While this approach
   // might not perfectly mirror the script loading ancestry in all complex
   // scenarios, it's considered sufficient for our tracking purposes.
-  ad_script_provenances_.insert(current_ad_script, ad_provenance->Clone());
+  ad_script_data_.insert(
+      script_id,
+      AdScriptData(AdScriptIdentifier(GetDebuggerIdForContext(v8_context),
+                                      script_id, script_name),
+                   ad_provenance->Clone()));
 }
 
 AdTracker::AdScriptAncestry AdTracker::GetAncestry(
@@ -469,18 +468,17 @@
   bool max_size_reached = false;
 
   // TODO(yaoxia): Determine if we should CHECK that that the script ID in each
-  // step is guaranteed to be present in `ad_script_provenances_`.
-  auto provenance_it = ad_script_provenances_.find(ad_script);
-  if (provenance_it == ad_script_provenances_.end()) {
+  // step is guaranteed to be present in `ad_script_data_`.
+  auto provenance_it = ad_script_data_.find(ad_script.id);
+  if (provenance_it == ad_script_data_.end()) {
     return ancestry;
   }
 
-  // The input `ad_script` may not have a name set, but anything stored in
-  // ad_script_provenances_ should, so prefer that AdScriptIdentifier.
-  ancestry.ancestry_chain.push_back(provenance_it->key);
+  ancestry.ancestry_chain.push_back(provenance_it->value.id);
 
-  while (provenance_it != ad_script_provenances_.end()) {
-    const std::unique_ptr<AdProvenance>& ad_provenance = provenance_it->value;
+  while (provenance_it != ad_script_data_.end()) {
+    const std::unique_ptr<AdProvenance>& ad_provenance =
+        provenance_it->value.provenance;
 
     bool root_reached = false;
     switch (ad_provenance->Type()) {
@@ -511,7 +509,7 @@
       break;
     }
 
-    provenance_it = ad_script_provenances_.find(ancestry.ancestry_chain.back());
+    provenance_it = ad_script_data_.find(ancestry.ancestry_chain.back().id);
   }
 
   base::UmaHistogramBoolean(
diff --git a/third_party/blink/renderer/core/frame/ad_tracker.h b/third_party/blink/renderer/core/frame/ad_tracker.h
index b3a2039d..153e8ee 100644
--- a/third_party/blink/renderer/core/frame/ad_tracker.h
+++ b/third_party/blink/renderer/core/frame/ad_tracker.h
@@ -202,6 +202,11 @@
   friend class AdTrackerSimTest;
   friend class AdTrackerTest;
 
+  struct AdScriptData {
+    AdScriptIdentifier id;
+    std::unique_ptr<AdProvenance> provenance;
+  };
+
   // Similar to the public IsAdScriptInStack method but instead of returning an
   // ancestry chain, it returns only one script (the most immediate one).
   bool IsAdScriptInStackHelper(
@@ -255,19 +260,11 @@
   HeapHashMap<WeakMember<ExecutionContext>, KnownAdScriptsAndProvenance>
       context_known_ad_scripts_;
 
-  // Maps the identifier of a detected ad script to its AdProvenance.
-  HashMap<AdScriptIdentifier, std::unique_ptr<AdProvenance>>
-      ad_script_provenances_;
+  // A map of all known ad script ids to their metadata.
+  HashMap<int, AdScriptData> ad_script_data_;
 
   // The number of ad-related async tasks currently running in the stack.
   int running_ad_async_tasks_ = 0;
-
-  // The known ad-related script ids.
-  // TODO(jkarlin): We don't use the debugger id in the
-  // AdScriptIdentifier for the AdTracker itself, it's just for dev-tools. See
-  // if we can remove it completely and just use script ids within the
-  // AdTracker.
-  HashMap<int, AdScriptIdentifier> ad_script_ids_;
 };
 
 template <>
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index d240b7d..646e7ba0 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit d240b7de4d30af0769390eea62a27c1e648e8401
+Subproject commit 646e7ba054335255c4186c6be09fee796b518b48
diff --git a/tools/metrics/histograms/metadata/signin/enums.xml b/tools/metrics/histograms/metadata/signin/enums.xml
index cb0a991..a7cf7d5 100644
--- a/tools/metrics/histograms/metadata/signin/enums.xml
+++ b/tools/metrics/histograms/metadata/signin/enums.xml
@@ -735,6 +735,11 @@
   <int value="28" label="Push Notification"/>
   <int value="29" label="K-Anonymity Service"/>
   <int value="30" label="Feedback Uploader"/>
+  <int value="31" label="Password Sharing Recipients Downloader"/>
+  <int value="32" label="Web History Service"/>
+  <int value="33" label="Composebox Query Controller"/>
+  <int value="34" label="Document Suggestions Service"/>
+  <int value="35" label="Enterprise Search Aggregator"/>
 </enum>
 
 <!-- LINT.ThenChange(//components/signin/public/identity_manager/oauth_consumer_ids.h:OAuthConsumerId) -->