Reland: Display message when Android-OS advanced-protection-mode changes
This CL displays message when Android-OS provided
advanced-protection-mode changes:
- On startup if state changed while Chrome was closed
- When the setting changed if Chrome is running
The CL was reverted because the CL attempted to do a native call
- PermissionsAndroidFeatureMap#isEnabled() prior to native being
ready.
BUG=401529207
TEST=AdvancedProtectionMediatorTest
Change-Id: Ia89aa50513d335e96f71807423d68fef660d9469
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6386729
Reviewed-by: Tomasz Wiszkowski <ender@google.com>
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: Thomas Nguyen <tungnh@chromium.org>
Reviewed-by: Javier Castro <jacastro@chromium.org>
Reviewed-by: Colin Blundell <blundell@chromium.org>
Reviewed-by: Xinghui Lu <xinghuilu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1437804}
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index cb6c7104..575ce76 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1086,6 +1086,7 @@
"//chrome/browser/readaloud/android:junit",
"//chrome/browser/recent_tabs:junit",
"//chrome/browser/recent_tabs/internal:junit",
+ "//chrome/browser/safe_browsing/android:junit",
"//chrome/browser/safety_check/android:junit",
"//chrome/browser/safety_hub/android:junit",
"//chrome/browser/search_engines/android:junit",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index ace633f..49063637 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -116,6 +116,7 @@
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.read_later.ReadLaterIphController;
import org.chromium.chrome.browser.readaloud.ReadAloudIphController;
+import org.chromium.chrome.browser.safe_browsing.AdvancedProtectionCoordinator;
import org.chromium.chrome.browser.search_engines.choice_screen.ChoiceDialogCoordinator;
import org.chromium.chrome.browser.share.ShareDelegate;
import org.chromium.chrome.browser.share.link_to_text.LinkToTextIphController;
@@ -249,6 +250,7 @@
private @Nullable LoadingFullscreenCoordinator mLoadingFullscreenCoordinator;
private @Nullable BookmarkOpener mBookmarkOpener;
private @NonNull ObservableSupplier<BookmarkManagerOpener> mBookmarkManagerOpenerSupplier;
+ private @NonNull AdvancedProtectionCoordinator mAdvancedProtectionCoordinator;
// Activity tab observer that updates the current tab used by various UI components.
private class RootUiTabObserver extends ActivityTabTabObserver {
@@ -625,6 +627,11 @@
mLoadingFullscreenCoordinator = null;
}
+ if (mAdvancedProtectionCoordinator != null) {
+ mAdvancedProtectionCoordinator.destroy();
+ mAdvancedProtectionCoordinator = null;
+ }
+
super.onDestroy();
}
@@ -739,6 +746,8 @@
super.onFinishNativeInitialization();
assert mLayoutManager != null;
+ mAdvancedProtectionCoordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+
UmaSessionStats.registerSyntheticFieldTrial(
"AndroidNavigationMode",
UiUtils.isGestureNavigationMode(mActivity.getWindow())
@@ -1541,6 +1550,10 @@
return true;
}
+ if (mAdvancedProtectionCoordinator.showMessageOnStartupIfNeeded()) {
+ return true;
+ }
+
return triggerPromo(profile, intentWithEffect);
}
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index 3de3e2f..96f3909a 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -252,8 +252,16 @@
"Chrome.RequestDesktopSiteGlobalSetting.DefaultEnabled";
/**
- * Indicates that Chrome should show an alert to the user about data privacy if the device
- * lock is removed.
+ * Indicates the state of the Android-OS-provided advanced-protection setting when Chrome was
+ * last opened. Used to determine whether to show on startup a message informing the user about
+ * the setting change.
+ */
+ public static final String DEFAULT_OS_ADVANCED_PROTECTION_SETTING =
+ "Chrome.OsAdvancedProtection.DefaultEnabled";
+
+ /**
+ * Indicates that Chrome should show an alert to the user about data privacy if the device lock
+ * is removed.
*/
public static final String DEVICE_LOCK_SHOW_ALERT_IF_REMOVED =
"Chrome.DeviceLock.ShowAlertIfRemoved";
@@ -1005,6 +1013,7 @@
DEFAULT_BROWSER_PROMO_PROMOED_COUNT,
DEFAULT_BROWSER_PROMO_SESSION_COUNT,
DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING,
+ DEFAULT_OS_ADVANCED_PROTECTION_SETTING,
DEPRECATED_HOMEPAGE_LOCATION_POLICY,
DEPRECATED_HOMEPAGE_PARTNER_CUSTOMIZED_DEFAULT_URI,
DEVICE_LOCK_SHOW_ALERT_IF_REMOVED,
diff --git a/chrome/browser/safe_browsing/android/BUILD.gn b/chrome/browser/safe_browsing/android/BUILD.gn
index 947aef5..7adfb06 100644
--- a/chrome/browser/safe_browsing/android/BUILD.gn
+++ b/chrome/browser/safe_browsing/android/BUILD.gn
@@ -44,6 +44,8 @@
android_library("java") {
sources = [
+ "java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionCoordinator.java",
+ "java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediator.java",
"java/src/org/chromium/chrome/browser/safe_browsing/SafeBrowsingBridge.java",
"java/src/org/chromium/chrome/browser/safe_browsing/settings/EnhancedProtectionSettingsFragment.java",
"java/src/org/chromium/chrome/browser/safe_browsing/settings/NoProtectionConfirmationDialog.java",
@@ -55,6 +57,7 @@
deps = [
":java_resources",
"//base:base_java",
+ "//base:supplier_java",
"//build/android:build_java",
"//chrome/browser/feedback/android:java",
"//chrome/browser/flags:java",
@@ -65,6 +68,9 @@
"//components/browser_ui/settings/android:java",
"//components/browser_ui/util/android:java",
"//components/browser_ui/widget/android:java",
+ "//components/messages/android:java",
+ "//components/permissions/android:core_java",
+ "//components/permissions/android:java",
"//components/prefs/android:java",
"//components/user_prefs/android:java",
"//content/public/android:content_java",
@@ -129,6 +135,28 @@
]
}
+robolectric_library("junit") {
+ sources = [ "java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java" ]
+ deps = [
+ ":java",
+ "//base:base_java_test_support",
+ "//base:base_junit_test_support",
+ "//base:base_shared_preferences_java",
+ "//base:service_loader_java",
+ "//base:unowned_user_data_java",
+ "//chrome/browser/preferences:java",
+ "//components/messages/android:factory_java",
+ "//components/messages/android:java",
+ "//components/messages/android:manager_java",
+ "//components/permissions/android:core_java",
+ "//components/permissions/android:java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ "//third_party/junit",
+ "//third_party/mockito:mockito_java",
+ "//ui/android:ui_java",
+ ]
+}
+
android_resources("java_resources") {
sources = [
"java/res/layout/radio_button_group_safe_browsing_preference.xml",
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionCoordinator.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionCoordinator.java
new file mode 100644
index 0000000..7df5e8a
--- /dev/null
+++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionCoordinator.java
@@ -0,0 +1,30 @@
+// 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.
+
+package org.chromium.chrome.browser.safe_browsing;
+
+import org.chromium.ui.base.WindowAndroid;
+
+/** A class for showing UI whenever the Android-OS-supplied advanced-protection state changes. */
+public class AdvancedProtectionCoordinator {
+ private AdvancedProtectionMediator mMediator;
+
+ public AdvancedProtectionCoordinator(WindowAndroid windowAndroid) {
+ mMediator = new AdvancedProtectionMediator(windowAndroid);
+ }
+
+ public void destroy() {
+ mMediator.destroy();
+ }
+
+ /**
+ * Shows message-UI informing the user about the Android-OS requested advanced-protection state
+ * if the advanced-protection state has changed since Chrome was last open.
+ *
+ * @return whether message-UI was shown.
+ */
+ public boolean showMessageOnStartupIfNeeded() {
+ return mMediator.showMessageOnStartupIfNeeded();
+ }
+}
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediator.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediator.java
new file mode 100644
index 0000000..66bee182
--- /dev/null
+++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediator.java
@@ -0,0 +1,93 @@
+// 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.
+
+package org.chromium.chrome.browser.safe_browsing;
+
+import static org.chromium.build.NullUtil.assumeNonNull;
+
+import androidx.annotation.NonNull;
+
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
+import org.chromium.components.messages.MessageDispatcherProvider;
+import org.chromium.components.permissions.OsAdditionalSecurityPermissionProvider;
+import org.chromium.components.permissions.OsAdditionalSecurityPermissionUtil;
+import org.chromium.components.permissions.PermissionsAndroidFeatureList;
+import org.chromium.components.permissions.PermissionsAndroidFeatureMap;
+import org.chromium.ui.base.WindowAndroid;
+
+/** A class for showing UI whenever the Android-OS-supplied advanced-protection state changes. */
+public class AdvancedProtectionMediator implements OsAdditionalSecurityPermissionProvider.Observer {
+ private WindowAndroid mWindowAndroid;
+
+ public AdvancedProtectionMediator(WindowAndroid windowAndroid) {
+ mWindowAndroid = windowAndroid;
+
+ var provider = OsAdditionalSecurityPermissionUtil.getProviderInstance();
+ if (provider != null
+ && !PermissionsAndroidFeatureMap.isEnabled(
+ PermissionsAndroidFeatureList
+ .OS_ADDITIONAL_SECURITY_PERMISSION_KILL_SWITCH)) {
+ provider.addObserver(this);
+ }
+ }
+
+ public void destroy() {
+ var provider = OsAdditionalSecurityPermissionUtil.getProviderInstance();
+ if (provider != null) {
+ provider.removeObserver(this);
+ }
+ }
+
+ public boolean showMessageOnStartupIfNeeded() {
+ if (PermissionsAndroidFeatureMap.isEnabled(
+ PermissionsAndroidFeatureList.OS_ADDITIONAL_SECURITY_PERMISSION_KILL_SWITCH)) {
+ return false;
+ }
+
+ var provider = OsAdditionalSecurityPermissionUtil.getProviderInstance();
+ if (provider == null) return false;
+
+ boolean cachedAdvancedProtectionSetting =
+ ChromeSharedPreferences.getInstance()
+ .readBoolean(
+ ChromePreferenceKeys.DEFAULT_OS_ADVANCED_PROTECTION_SETTING,
+ /* defaultValue= */ false);
+ if (cachedAdvancedProtectionSetting == provider.isAdvancedProtectionRequestedByOs()) {
+ return false;
+ }
+
+ updatePref(provider);
+ enqueueMessage(provider);
+ return true;
+ }
+
+ @Override
+ public void onAdvancedProtectionOsSettingChanged() {
+ var provider = OsAdditionalSecurityPermissionUtil.getProviderInstance();
+ if (provider == null) return;
+
+ updatePref(provider);
+ enqueueMessage(provider);
+ }
+
+ private void enqueueMessage(@NonNull OsAdditionalSecurityPermissionProvider provider) {
+ var context = assumeNonNull(mWindowAndroid.getContext()).get();
+ var propertyModel =
+ provider.buildAdvancedProtectionMessagePropertyModel(
+ context, /* primaryButtonAction= */ null);
+ if (propertyModel == null) {
+ return;
+ }
+ MessageDispatcherProvider.from(mWindowAndroid)
+ .enqueueWindowScopedMessage(propertyModel, /* highPriority= */ false);
+ }
+
+ private void updatePref(@NonNull OsAdditionalSecurityPermissionProvider provider) {
+ ChromeSharedPreferences.getInstance()
+ .writeBoolean(
+ ChromePreferenceKeys.DEFAULT_OS_ADVANCED_PROTECTION_SETTING,
+ provider.isAdvancedProtectionRequestedByOs());
+ }
+}
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java
new file mode 100644
index 0000000..bfcba66
--- /dev/null
+++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java
@@ -0,0 +1,249 @@
+// 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.
+
+package org.chromium.chrome.browser.safe_browsing;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.ServiceLoaderUtil;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.UnownedUserDataHost;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Features.DisableFeatures;
+import org.chromium.base.test.util.Features.EnableFeatures;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
+import org.chromium.components.messages.ManagedMessageDispatcher;
+import org.chromium.components.messages.MessagesFactory;
+import org.chromium.components.permissions.OsAdditionalSecurityPermissionProvider;
+import org.chromium.components.permissions.OsAdditionalSecurityPermissionUtil;
+import org.chromium.components.permissions.PermissionsAndroidFeatureList;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.lang.ref.WeakReference;
+
+/** Tests for {@link AdvancedProtectionMediator}. */
+@RunWith(BaseRobolectricTestRunner.class)
+@DisableFeatures(PermissionsAndroidFeatureList.OS_ADDITIONAL_SECURITY_PERMISSION_KILL_SWITCH)
+@Config(manifest = Config.NONE)
+public class AdvancedProtectionMediatorTest {
+ @Mock private WindowAndroid mWindowAndroid;
+ @Mock private Context mContext;
+ private WeakReference<Context> mWeakContext = new WeakReference<Context>(mContext);
+ private final UnownedUserDataHost mWindowUserDataHost = new UnownedUserDataHost();
+
+ @Mock private ManagedMessageDispatcher mMessageDispatcher;
+
+ private static class TestPermissionProvider extends OsAdditionalSecurityPermissionProvider {
+ private boolean mIsAdvancedProtectionRequestedByOs;
+ private Observer mObserver;
+
+ public TestPermissionProvider(boolean isAdvancedProtectionRequestedByOs) {
+ mIsAdvancedProtectionRequestedByOs = isAdvancedProtectionRequestedByOs;
+ }
+
+ @Override
+ public void addObserver(Observer observer) {
+ assert mObserver == null;
+ mObserver = observer;
+ }
+
+ @Override
+ public boolean isAdvancedProtectionRequestedByOs() {
+ return mIsAdvancedProtectionRequestedByOs;
+ }
+
+ @Override
+ public @Nullable PropertyModel buildAdvancedProtectionMessagePropertyModel(
+ Context context, Runnable primaryButtonAction) {
+ return new PropertyModel();
+ }
+
+ public void setAdvancedProtectionRequestedByOs(boolean isAdvancedProtectionRequestedByOs) {
+ mIsAdvancedProtectionRequestedByOs = isAdvancedProtectionRequestedByOs;
+ if (mObserver != null) {
+ mObserver.onAdvancedProtectionOsSettingChanged();
+ }
+ }
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mWindowAndroid.getUnownedUserDataHost()).thenReturn(mWindowUserDataHost);
+ when(mWindowAndroid.getContext()).thenReturn(mWeakContext);
+ MessagesFactory.attachMessageDispatcher(mWindowAndroid, mMessageDispatcher);
+
+ ContextUtils.getAppSharedPreferences().edit().clear();
+ OsAdditionalSecurityPermissionUtil.resetForTesting();
+ }
+
+ private TestPermissionProvider setPermissionProvider(
+ boolean isAdvancedProtectionRequestedByOs) {
+ var provider = new TestPermissionProvider(isAdvancedProtectionRequestedByOs);
+ ThreadUtils.runOnUiThreadBlocking(
+ () -> {
+ ServiceLoaderUtil.setInstanceForTesting(
+ OsAdditionalSecurityPermissionProvider.class, provider);
+ });
+ return provider;
+ }
+
+ private void verifyEnqueuedMessage() {
+ verify(mMessageDispatcher, times(1)).enqueueWindowScopedMessage(any(), anyBoolean());
+ }
+
+ private void verifyDidNotEnqueueMessage() {
+ verify(mMessageDispatcher, times(0)).enqueueWindowScopedMessage(any(), anyBoolean());
+ }
+
+ /**
+ * Test that {@link AdvancedProtectionCoordinator#showMessageOnStartupIfNeeded()} does not show
+ * a message if the pref is not stored and advanced-protection-mode is off.
+ */
+ @Test
+ public void testDontShowMessageNoPrefAdvancedProtectionOff() {
+ setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ false);
+
+ var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+ coordinator.showMessageOnStartupIfNeeded();
+ verifyDidNotEnqueueMessage();
+
+ coordinator.destroy();
+ }
+
+ /**
+ * Test that {@link AdvancedProtectionCoordinator#showMessageOnStartupIfNeeded()} shows a
+ * message if the pref is not stored and advanced-protection-mode is on.
+ */
+ @Test
+ public void testShowMessageNoPrefAdvancedProtectionOn() {
+ setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ true);
+
+ var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+ coordinator.showMessageOnStartupIfNeeded();
+ verifyEnqueuedMessage();
+
+ coordinator.destroy();
+ }
+
+ /**
+ * Test that {@link AdvancedProtectionCoordinator#showMessageOnStartupIfNeeded()} does not show
+ * a message if a pref is stored and its value matches the current advanced-protection-mode
+ * state.
+ */
+ @Test
+ public void testDontShowMessagePrefMatches() {
+ ChromeSharedPreferences.getInstance()
+ .writeBoolean(ChromePreferenceKeys.DEFAULT_OS_ADVANCED_PROTECTION_SETTING, true);
+ setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ true);
+
+ var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+ coordinator.showMessageOnStartupIfNeeded();
+ verifyDidNotEnqueueMessage();
+
+ coordinator.destroy();
+ }
+
+ /**
+ * Test that {@link AdvancedProtectionCoordinator#showMessageOnStartupIfNeeded()} shows a
+ * message if a pref is stored and its value is true and advanced-protection-mode is off.
+ */
+ @Test
+ public void testShowMessagePrefTrueAndDiffers() {
+ var sharedPreferences = ChromeSharedPreferences.getInstance();
+ sharedPreferences.writeBoolean(
+ ChromePreferenceKeys.DEFAULT_OS_ADVANCED_PROTECTION_SETTING, true);
+ setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ false);
+
+ var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+ coordinator.showMessageOnStartupIfNeeded();
+ verifyEnqueuedMessage();
+
+ assertFalse(
+ sharedPreferences.readBoolean(
+ ChromePreferenceKeys.DEFAULT_OS_ADVANCED_PROTECTION_SETTING,
+ /* defaultValue= */ false));
+
+ coordinator.destroy();
+ }
+
+ /**
+ * Test that {@link AdvancedProtectionCoordinator#showMessageOnStartupIfNeeded()} shows a
+ * message if a pref is stored and its value is false and advanced-protection-mode is on.
+ */
+ @Test
+ public void testShowMessagePrefFalseAndDiffers() {
+ var sharedPreferences = ChromeSharedPreferences.getInstance();
+ sharedPreferences.writeBoolean(
+ ChromePreferenceKeys.DEFAULT_OS_ADVANCED_PROTECTION_SETTING, false);
+ setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ true);
+
+ var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+ coordinator.showMessageOnStartupIfNeeded();
+ verifyEnqueuedMessage();
+
+ assertTrue(
+ sharedPreferences.readBoolean(
+ ChromePreferenceKeys.DEFAULT_OS_ADVANCED_PROTECTION_SETTING,
+ /* defaultValue= */ false));
+
+ coordinator.destroy();
+ }
+
+ /**
+ * Test that message is shown when advanced-protection-state is changed while Chrome is running.
+ */
+ @Test
+ public void testShowMessageOnStateChange() {
+ var sharedPreferences = ChromeSharedPreferences.getInstance();
+ sharedPreferences.writeBoolean(
+ ChromePreferenceKeys.DEFAULT_OS_ADVANCED_PROTECTION_SETTING, true);
+ var provider = setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ true);
+
+ var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+ coordinator.showMessageOnStartupIfNeeded();
+ verifyDidNotEnqueueMessage();
+ provider.setAdvancedProtectionRequestedByOs(/* isAdvancedProtectionRequestedByOs= */ false);
+ verifyEnqueuedMessage();
+
+ coordinator.destroy();
+ }
+
+ /** Test that a message is not shown when the feature-kill-switch is set. */
+ @Test
+ @EnableFeatures({PermissionsAndroidFeatureList.OS_ADDITIONAL_SECURITY_PERMISSION_KILL_SWITCH})
+ public void testDontShowMessageKillSwitch() {
+ var sharedPreferences = ChromeSharedPreferences.getInstance();
+ sharedPreferences.writeBoolean(
+ ChromePreferenceKeys.DEFAULT_OS_ADVANCED_PROTECTION_SETTING, true);
+ var provider = setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ false);
+
+ var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+ coordinator.showMessageOnStartupIfNeeded();
+ verifyDidNotEnqueueMessage();
+ provider.setAdvancedProtectionRequestedByOs(/* isAdvancedProtectionRequestedByOs= */ true);
+ verifyDidNotEnqueueMessage();
+
+ coordinator.destroy();
+ }
+}
diff --git a/components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java b/components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java
index dad5657..b5dd7be 100644
--- a/components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java
+++ b/components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java
@@ -373,6 +373,8 @@
return "CctAccountMismatchNotice";
case MessageIdentifier.PROMPT_HATS_CLEAR_BROWSING_DATA:
return "PromptHatsClearBrowsingData";
+ case MessageIdentifier.OS_ADVANCED_PROTECTION_SETTING_CHANGED_MESSAGE:
+ return "OsAdvancedProtectionSettingChangedMessage";
default:
return "Unknown";
}
diff --git a/components/messages/android/message_enums.h b/components/messages/android/message_enums.h
index 776fe74..af88289 100644
--- a/components/messages/android/message_enums.h
+++ b/components/messages/android/message_enums.h
@@ -142,6 +142,7 @@
COLLABORATION_REMOVED = 57,
CCT_ACCOUNT_MISMATCH_NOTICE = 58,
PROMPT_HATS_CLEAR_BROWSING_DATA = 59,
+ OS_ADVANCED_PROTECTION_SETTING_CHANGED_MESSAGE = 60,
// Insert new values before this line.
COUNT
};
diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/OsAdditionalSecurityPermissionProvider.java b/components/permissions/android/java/src/org/chromium/components/permissions/OsAdditionalSecurityPermissionProvider.java
index ae08713..c89a5ce2 100644
--- a/components/permissions/android/java/src/org/chromium/components/permissions/OsAdditionalSecurityPermissionProvider.java
+++ b/components/permissions/android/java/src/org/chromium/components/permissions/OsAdditionalSecurityPermissionProvider.java
@@ -6,7 +6,10 @@
import android.content.Context;
+import androidx.annotation.Nullable;
+
import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.modelutil.PropertyModel;
/**
* Placeholder provider class to query whether the operating system has granted various security
@@ -14,11 +17,30 @@
*/
@NullMarked
public abstract class OsAdditionalSecurityPermissionProvider {
+ public interface Observer {
+ /** Called when the Android-OS advanced-protection-mode setting changes. */
+ void onAdvancedProtectionOsSettingChanged();
+ }
+
+ public void addObserver(Observer observer) {}
+
+ public void removeObserver(Observer observer) {}
+
+ /**
+ * Returns whether the Android OS requests advanced-protection-mode. Implementations must allow
+ * querying from any thread.
+ */
+ public boolean isAdvancedProtectionRequestedByOs() {
+ return !hasJavascriptOptimizerPermission();
+ }
+
/**
* Returns whether the operating system has granted permission to enable javascript optimizers.
* Implementations must allow querying from any thread.
*/
- public abstract boolean hasJavascriptOptimizerPermission();
+ public boolean hasJavascriptOptimizerPermission() {
+ return false;
+ }
/**
* Returns message to display in site settings explaining why the operating system has denied
@@ -27,4 +49,15 @@
public String getJavascriptOptimizerMessage(Context context) {
return "";
}
+
+ /**
+ * Returns {@link PropertyModel} for message-UI to notify user about new
+ * advanced-protection-mode state.
+ *
+ * @param primaryButtonAction The action to run when the message-UI primary-button is clicked.
+ */
+ public @Nullable PropertyModel buildAdvancedProtectionMessagePropertyModel(
+ Context context, Runnable primaryButtonAction) {
+ return null;
+ }
}
diff --git a/tools/metrics/histograms/metadata/android/enums.xml b/tools/metrics/histograms/metadata/android/enums.xml
index 2f194378..12b2170 100644
--- a/tools/metrics/histograms/metadata/android/enums.xml
+++ b/tools/metrics/histograms/metadata/android/enums.xml
@@ -1154,6 +1154,7 @@
<int value="57" label="CollaborationRemoved"/>
<int value="58" label="CctAccountMismatchNotice"/>
<int value="59" label="PromptHatsClearBrowsingData"/>
+ <int value="60" label="OsAdvancedProtectionSettingChangedMessage"/>
</enum>
<!-- LINT.ThenChange(//components/messages/android/message_enums.h:MessageIdentifier) -->
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index 7fbd26f..f52ae5d 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -177,6 +177,7 @@
<variant name=".NearOomReduction"/>
<variant name=".NotificationBlocked"/>
<variant name=".OfferNotification"/>
+ <variant name=".OsAdvancedProtectionSettingChangedMessage"/>
<variant name=".PermissionBlocked"/>
<variant name=".PermissionUpdate"/>
<variant name=".PopupBlocked"/>