Commit f20ff634 authored by Josh Simmons's avatar Josh Simmons Committed by Chromium LUCI CQ

Gate voice search behind the AudioCaptureAllowed policy.

As we intend to merge this into 88, this check is controllable via the VoiceSearchAudioCapturePolicy feature.

To keep this change small, hiding the mic is best-effort. There are cases where the user's profile is not yet available when layout decisions are being made. In those cases, we will continue to show the voice search mics, but will not initiate a voice search when the mics are pressed. Future CLs will add observers so the mic surfaces can be hidden as soon as the profile is available.

Bug: 1161022
Change-Id: I772788288dc41b610f996c0b631e83e5cba117ef
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2598008
Commit-Queue: Josh Simmons <jds@google.com>
Reviewed-by: default avatarFilip Gorski <fgorski@chromium.org>
Cr-Commit-Position: refs/heads/master@{#839051}
parent 9e53f70c
......@@ -26,12 +26,17 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.profiles.ProfileManager;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.util.VoiceRecognitionUtil;
import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.content_public.browser.NavigationHandle;
import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.content_public.browser.WebContents;
......@@ -461,6 +466,15 @@ public class VoiceRecognitionHandler {
return results;
}
/** Returns the PrefService for the active Profile, or null if no profile has been loaded. */
private @Nullable PrefService getPrefService() {
if (!ProfileManager.isInitialized()) {
return null;
}
return UserPrefs.get(Profile.getLastUsedRegularProfile());
}
/**
* Triggers a voice recognition intent to allow the user to specify a search query.
*
......@@ -475,6 +489,20 @@ public class VoiceRecognitionHandler {
Activity activity = windowAndroid.getActivity().get();
if (activity == null) return;
if (FeatureList.isInitialized()
&& ChromeFeatureList.isEnabled(
ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY)) {
// TODO(crbug.com/1161022): Rather than checking here we should instead hide the mics
// when disabled via policy. Since the policy isn't available at layout time, we'll need
// to add observers that can notify the different mic surfaces of voice search being
// disabled.
@Nullable
PrefService prefService = getPrefService();
if (prefService == null || !prefService.getBoolean(Pref.AUDIO_CAPTURE_ALLOWED)) {
return;
}
}
if (startAGSAForAssistantVoiceSearch(activity, windowAndroid, source)) return;
if (!startSystemForVoiceSearch(activity, windowAndroid, source)) {
......@@ -665,6 +693,19 @@ public class VoiceRecognitionHandler {
return false;
}
if (FeatureList.isInitialized()
&& ChromeFeatureList.isEnabled(
ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY)) {
@Nullable
PrefService prefService = getPrefService();
// If the PrefService isn't initialized yet we won't know here whether or not voice
// search is allowed by policy. In that case, treat voice search as enabled but check
// again before starting voice search.
if (prefService != null && !prefService.getBoolean(Pref.AUDIO_CAPTURE_ALLOWED)) {
return false;
}
}
Activity activity = windowAndroid.getActivity().get();
return activity != null && isRecognitionIntentPresent(true);
}
......
......@@ -48,6 +48,7 @@ import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionsDropdow
import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler.AssistantActionPerformed;
import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler.VoiceInteractionSource;
import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler.VoiceResult;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
......@@ -58,6 +59,7 @@ import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.components.metrics.OmniboxEventProtos.OmniboxEventProto.PageClassification;
import org.chromium.components.omnibox.AutocompleteResult;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.base.ActivityWindowAndroid;
import org.chromium.ui.base.AndroidPermissionDelegate;
......@@ -564,27 +566,27 @@ public class VoiceRecognitionHandlerTest {
@Test
@SmallTest
public void testIsVoiceSearchEnabled_FalseOnNullTab() {
Assert.assertFalse(mHandler.isVoiceSearchEnabled());
Assert.assertFalse(isVoiceSearchEnabled());
}
@Test
@SmallTest
public void testIsVoiceSearchEnabled_FalseOnNullDataProvider() {
mDataProvider = null;
Assert.assertFalse(mHandler.isVoiceSearchEnabled());
Assert.assertFalse(isVoiceSearchEnabled());
}
@Test
@SmallTest
public void testIsVoiceSearchEnabled_FalseWhenIncognito() {
mDataProvider.setIncognito(true);
Assert.assertFalse(mHandler.isVoiceSearchEnabled());
Assert.assertFalse(isVoiceSearchEnabled());
}
@Test
@SmallTest
public void testIsVoiceSearchEnabled_FalseWhenNoPermissionAndCantRequestPermission() {
Assert.assertFalse(mHandler.isVoiceSearchEnabled());
Assert.assertFalse(isVoiceSearchEnabled());
Assert.assertTrue(mPermissionDelegate.calledHasPermission());
Assert.assertTrue(mPermissionDelegate.calledCanRequestPermission());
}
......@@ -594,7 +596,56 @@ public class VoiceRecognitionHandlerTest {
public void testIsVoiceSearchEnabled_Success() {
mPermissionDelegate.setCanRequestPermission(true);
mPermissionDelegate.setHasPermission(true);
Assert.assertTrue(mHandler.isVoiceSearchEnabled());
Assert.assertTrue(isVoiceSearchEnabled());
}
@Test
@SmallTest
@Feature("VoiceSearchAudioCapturePolicy")
@EnableFeatures({ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY})
public void testIsVoiceSearchEnabled_AllowedByPolicy() {
setAudioCapturePref(true);
mPermissionDelegate.setCanRequestPermission(true);
mPermissionDelegate.setHasPermission(true);
Assert.assertTrue(isVoiceSearchEnabled());
}
@Test
@SmallTest
@Feature("VoiceSearchAudioCapturePolicy")
@EnableFeatures({ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY})
public void testIsVoiceSearchEnabled_DisabledByPolicy() {
setAudioCapturePref(false);
mPermissionDelegate.setCanRequestPermission(true);
mPermissionDelegate.setHasPermission(true);
Assert.assertFalse(isVoiceSearchEnabled());
}
@Test
@SmallTest
@Feature("VoiceSearchAudioCapturePolicy")
@EnableFeatures({ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY})
public void testIsVoiceSearchEnabled_AudioCapturePolicyAllowsByDefault() {
mPermissionDelegate.setCanRequestPermission(true);
mPermissionDelegate.setHasPermission(true);
Assert.assertTrue(isVoiceSearchEnabled());
}
@Test
@SmallTest
@Feature("VoiceSearchAudioCapturePolicy")
@DisableFeatures({ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY})
public void testIsVoiceSearchEnabled_SkipPolicyCheckWhenDisabled() {
setAudioCapturePref(false);
mPermissionDelegate.setCanRequestPermission(true);
mPermissionDelegate.setHasPermission(true);
Assert.assertTrue(isVoiceSearchEnabled());
}
/** Calls isVoiceSearchEnabled(), ensuring it is run on the UI thread. */
private boolean isVoiceSearchEnabled() {
return TestThreadUtils.runOnUiThreadBlockingNoException(
() -> mHandler.isVoiceSearchEnabled());
}
/**
......@@ -746,6 +797,60 @@ public class VoiceRecognitionHandlerTest {
Assert.assertFalse(mDelegate.updatedMicButtonState());
}
@Test
@SmallTest
@Feature("VoiceSearchAudioCapturePolicy")
@EnableFeatures({ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY,
ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH})
public void
testStartVoiceRecognition_AudioCaptureAllowedByPolicy() {
setAudioCapturePref(true);
doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch();
startVoiceRecognition(VoiceInteractionSource.TOOLBAR);
Assert.assertTrue(mWindowAndroid.wasCancelableIntentShown());
}
@Test
@SmallTest
@Feature("VoiceSearchAudioCapturePolicy")
@EnableFeatures({ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY,
ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH})
public void
testStartVoiceRecognition_AudioCaptureDisabledByPolicy() {
setAudioCapturePref(false);
doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch();
startVoiceRecognition(VoiceInteractionSource.TOOLBAR);
Assert.assertFalse(mWindowAndroid.wasCancelableIntentShown());
}
@Test
@SmallTest
@Feature("VoiceSearchAudioCapturePolicy")
@EnableFeatures({ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY,
ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH})
public void
testStartVoiceRecognition_AudioCapturePolicyAllowsByDefault() {
doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch();
startVoiceRecognition(VoiceInteractionSource.TOOLBAR);
Assert.assertTrue(mWindowAndroid.wasCancelableIntentShown());
}
@Test
@SmallTest
@Feature("VoiceSearchAudioCapturePolicy")
@EnableFeatures({ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH})
@DisableFeatures({ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY})
public void testStartVoiceRecognition_SkipPolicyWhenFeatureDisabled() {
setAudioCapturePref(false);
doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch();
startVoiceRecognition(VoiceInteractionSource.TOOLBAR);
Assert.assertTrue(mWindowAndroid.wasCancelableIntentShown());
}
/**
* Tests for the {@link VoiceRecognitionHandler.VoiceRecognitionCompleteCallback}.
*
......@@ -1122,4 +1227,11 @@ public class VoiceRecognitionHandlerTest {
}
}
}
private static void setAudioCapturePref(boolean value) {
TestThreadUtils.runOnUiThreadBlocking(() -> {
UserPrefs.get(Profile.getLastUsedRegularProfile())
.setBoolean(Pref.AUDIO_CAPTURE_ALLOWED, value);
});
}
}
......@@ -380,6 +380,7 @@ public class ReengagementNotificationControllerIntegrationTest {
features.put(ChromeFeatureList.SEARCH_ENGINE_PROMO_EXISTING_DEVICE, false);
features.put(ChromeFeatureList.OMNIBOX_SEARCH_ENGINE_LOGO, false);
features.put(ChromeFeatureList.SHARE_BY_DEFAULT_IN_CCT, true);
features.put(ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY, false);
FeatureList.setTestFeatures(features);
}
}
......@@ -248,6 +248,7 @@ const base::Feature* kFeaturesExposedToJava[] = {
&kUmaBackgroundSessions,
&kUpdateNotificationSchedulingIntegration,
&kUpdateNotificationScheduleServiceImmediateShowOption,
&kVoiceSearchAudioCapturePolicy,
&kVoiceButtonInTopToolbar,
&kVrBrowsingFeedback,
&kPrefetchNotificationSchedulingIntegration,
......@@ -713,6 +714,9 @@ const base::Feature kUpdateNotificationScheduleServiceImmediateShowOption{
const base::Feature kUserMediaScreenCapturing{
"UserMediaScreenCapturing", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kVoiceSearchAudioCapturePolicy{
"VoiceSearchAudioCapturePolicy", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kVoiceButtonInTopToolbar{"VoiceButtonInTopToolbar",
base::FEATURE_DISABLED_BY_DEFAULT};
......
......@@ -148,6 +148,7 @@ extern const base::Feature kUpdateNotificationSchedulingIntegration;
extern const base::Feature
kUpdateNotificationScheduleServiceImmediateShowOption;
extern const base::Feature kUserMediaScreenCapturing;
extern const base::Feature kVoiceSearchAudioCapturePolicy;
extern const base::Feature kVoiceButtonInTopToolbar;
extern const base::Feature kVrBrowsingFeedback;
extern const base::Feature kPrefetchNotificationSchedulingIntegration;
......
......@@ -471,6 +471,7 @@ public abstract class ChromeFeatureList {
public static final String UPDATE_NOTIFICATION_IMMEDIATE_SHOW_OPTION =
"UpdateNotificationScheduleServiceImmediateShowOption";
public static final String USE_CHIME_ANDROID_SDK = "UseChimeAndroidSdk";
public static final String VOICE_SEARCH_AUDIO_CAPTURE_POLICY = "VoiceSearchAudioCapturePolicy";
public static final String VOICE_BUTTON_IN_TOP_TOOLBAR = "VoiceButtonInTopToolbar";
public static final String VR_BROWSING_FEEDBACK = "VrBrowsingFeedback";
public static final String WEB_AUTH = "WebAuthentication";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment