blob: 73e4ef4f03b48b77cf4a94c6151d531a9c88d869 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// 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.flags;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.speech.RecognizerIntent;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.BuildInfo;
import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.FieldTrialList;
import org.chromium.base.PackageManagerUtils;
import org.chromium.base.SysUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.device.DeviceClassManager;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider;
import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager;
import org.chromium.ui.base.DeviceFormFactor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A utility {@code class} meant to help determine whether or not certain features are supported by
* this device.
*
* This utility class also contains support for cached feature flags that must take effect on
* startup before native is initialized but are set via native code. The caching is done in
* {@link android.content.SharedPreferences}, which is available in Java immediately.
*
* To cache the flag {@link ChromeFeatureList}.FOO:
* - Call {@link FeatureUtilities#cacheFlag(String, String)} in {@link
* FeatureUtilities#cacheNativeFlags()} passing
* {@link ChromePreferenceKeys#FLAGS_CACHED}.createKey(FOO) and FOO.
* - To query whether the cached flag is enabled in client code, call
* {@link FeatureUtilities#isFlagEnabled(String, boolean)} passing
* {@link ChromePreferenceKeys#FLAGS_CACHED}.createKey(FOO).
* Consider this the source of truth for whether the flag is turned on in the current session.
* - When querying whether a cached feature is enabled from native, a @CalledByNative method can be
* exposed in this file to allow feature_utilities.cc to retrieve the cached value.
*
* For cached flags that are queried before native is initialized, when a new experiment
* configuration is received the metrics reporting system will record metrics as if the
* experiment is enabled despite the experimental behavior not yet taking effect. This will be
* remedied on the next process restart, when the static Boolean is reset to the newly cached
* value in shared preferences.
*/
public class FeatureUtilities {
private static Map<String, Boolean> sFlags = new HashMap<>();
private static Boolean sHasRecognitionIntentHandler;
private static String sReachedCodeProfilerTrialGroup;
/**
* Determines whether or not the {@link RecognizerIntent#ACTION_WEB_SEARCH} {@link Intent}
* is handled by any {@link android.app.Activity}s in the system. The result will be cached for
* future calls. Passing {@code false} to {@code useCachedValue} will force it to re-query any
* {@link android.app.Activity}s that can process the {@link Intent}.
* @param useCachedValue Whether or not to use the cached value from a previous result.
* @return {@code true} if recognition is supported. {@code false} otherwise.
*/
public static boolean isRecognitionIntentPresent(boolean useCachedValue) {
ThreadUtils.assertOnUiThread();
if (sHasRecognitionIntentHandler == null || !useCachedValue) {
List<ResolveInfo> activities = PackageManagerUtils.queryIntentActivities(
new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
sHasRecognitionIntentHandler = !activities.isEmpty();
}
return sHasRecognitionIntentHandler;
}
/**
* Records the current custom tab visibility state with native-side feature utilities.
* @param visible Whether a custom tab is visible.
*/
public static void setCustomTabVisible(boolean visible) {
FeatureUtilitiesJni.get().setCustomTabVisible(visible);
}
/**
* Records whether the activity is in multi-window mode with native-side feature utilities.
* @param isInMultiWindowMode Whether the activity is in Android N multi-window mode.
*/
public static void setIsInMultiWindowMode(boolean isInMultiWindowMode) {
FeatureUtilitiesJni.get().setIsInMultiWindowMode(isInMultiWindowMode);
}
/**
* Records the type of the currently visible Activity for metrics.
* @param activityType The type of the Activity.
*/
public static void setActivityType(@ActivityType int activityType) {
FeatureUtilitiesJni.get().setActivityType(activityType);
}
/**
* Caches flags that must take effect on startup but are set via native code.
*/
public static void cacheNativeFlags() {
cacheCommandLineOnNonRootedEnabled();
cacheBottomToolbarEnabled();
cacheAdaptiveToolbarEnabled();
cacheLabeledBottomToolbarEnabled();
cacheNightModeAvailable();
cacheNightModeDefaultToLight();
cacheNightModeForCustomTabsAvailable();
cacheDownloadAutoResumptionEnabledInNative();
cachePrioritizeBootstrapTasks();
cacheFeedEnabled();
cacheNetworkServiceWarmUpEnabled();
cacheImmersiveUiModeEnabled();
cacheSwapPixelFormatToFixConvertFromTranslucentEnabled();
cacheReachedCodeProfilerTrialGroup();
cacheStartSurfaceEnabled();
cacheNativeTabSwitcherUiFlags();
cacheHomepageLocationPolicyEnabled();
cachePaintPreviewTestEnabled();
// Propagate REACHED_CODE_PROFILER feature value to LibraryLoader. This can't be done in
// LibraryLoader itself because it lives in //base and can't depend on ChromeFeatureList.
LibraryLoader.setReachedCodeProfilerEnabledOnNextRuns(
ChromeFeatureList.isEnabled(ChromeFeatureList.REACHED_CODE_PROFILER));
}
/**
* Caches flags that are enabled in ServiceManager only mode and must take effect on startup but
* are set via native code. This function needs to be called in ServiceManager only mode to mark
* these field trials as active, otherwise histogram data recorded in ServiceManager only mode
* won't be tagged with their corresponding field trial experiments.
*/
public static void cacheNativeFlagsForServiceManagerOnlyMode() {
// TODO(crbug.com/995355): Move other related flags from {@link cacheNativeFlags} to here.
cacheServiceManagerForDownloadResumption();
cacheServiceManagerForBackgroundPrefetch();
}
/**
* @return True if tab model merging for Android N+ is enabled.
*/
public static boolean isTabModelMergingEnabled() {
if (CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_TAB_MERGING_FOR_TESTING)) {
return false;
}
return Build.VERSION.SDK_INT > Build.VERSION_CODES.M;
}
private static void cacheServiceManagerForDownloadResumption() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_SERVICE_MANAGER_FOR_DOWNLOAD_RESUMPTION,
ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD);
}
/**
* @return if DownloadResumptionBackgroundTask should load native in service manager only mode.
*/
public static boolean isServiceManagerForDownloadResumptionEnabled() {
return isFlagEnabled(
ChromePreferenceKeys.FLAGS_CACHED_SERVICE_MANAGER_FOR_DOWNLOAD_RESUMPTION, false);
}
public static void cacheServiceManagerForBackgroundPrefetch() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_SERVICE_MANAGER_FOR_BACKGROUND_PREFETCH,
ChromeFeatureList.SERVICE_MANAGER_FOR_BACKGROUND_PREFETCH);
}
/**
* @return if PrefetchBackgroundTask should load native in service manager only mode.
*/
public static boolean isServiceManagerForBackgroundPrefetchEnabled() {
return isFlagEnabled(
ChromePreferenceKeys.FLAGS_CACHED_SERVICE_MANAGER_FOR_BACKGROUND_PREFETCH,
false)
&& isFeedEnabled();
}
/**
* Cache the value of the flag whether or not to use Feed so it can be checked in Java before
* native is loaded.
*/
public static void cacheFeedEnabled() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_INTEREST_FEED_CONTENT_SUGGESTIONS,
ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS);
}
/**
* @return Whether or not the Feed is enabled (based on the cached value in SharedPrefs).
*/
public static boolean isFeedEnabled() {
return isFlagEnabled(
ChromePreferenceKeys.FLAGS_CACHED_INTEREST_FEED_CONTENT_SUGGESTIONS, false);
}
/**
* @return Whether or not the download auto-resumptions should be enabled in native.
*/
@CalledByNative
public static boolean isDownloadAutoResumptionEnabledInNative() {
return isFlagEnabled(
ChromePreferenceKeys.FLAGS_CACHED_DOWNLOAD_AUTO_RESUMPTION_IN_NATIVE, true);
}
/**
* Cache whether or not the bottom toolbar is enabled so on next startup, the value can
* be made available immediately.
*/
public static void cacheBottomToolbarEnabled() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_BOTTOM_TOOLBAR_ENABLED,
ChromeFeatureList.CHROME_DUET);
cacheBottomToolbarVariation();
}
/**
* Cache the enabled bottom toolbar variation.
*/
public static void cacheBottomToolbarVariation() {
cacheVariation(ChromePreferenceKeys.VARIATION_CACHED_BOTTOM_TOOLBAR,
ChromeFeatureList.CHROME_DUET,
BottomToolbarVariationManager.getVariationParamName());
}
/**
* Cache whether or not the adaptive toolbar is enabled so on next startup, the value can
* be made available immediately.
*/
public static void cacheAdaptiveToolbarEnabled() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_ADAPTIVE_TOOLBAR_ENABLED,
ChromeFeatureList.CHROME_DUET_ADAPTIVE);
}
/**
* Cache whether or not the labeled bottom toolbar is enabled so on next startup, the value can
* be made available immediately.
*/
public static void cacheLabeledBottomToolbarEnabled() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_LABELED_BOTTOM_TOOLBAR_ENABLED,
ChromeFeatureList.CHROME_DUET_LABELED);
}
/**
* Cache whether or not download auto-resumptions are enabled in native so on next startup, the
* value can be made available immediately.
*/
private static void cacheDownloadAutoResumptionEnabledInNative() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_DOWNLOAD_AUTO_RESUMPTION_IN_NATIVE,
ChromeFeatureList.DOWNLOADS_AUTO_RESUMPTION_NATIVE);
}
@VisibleForTesting
public static void setDownloadAutoResumptionEnabledInNativeForTesting(Boolean value) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED_DOWNLOAD_AUTO_RESUMPTION_IN_NATIVE, value);
}
/**
* @return Whether or not the bottom toolbar is enabled.
*/
public static boolean isBottomToolbarEnabled() {
// TODO(crbug.com/944228): TabGroupsAndroid and ChromeDuet are incompatible for now.
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_BOTTOM_TOOLBAR_ENABLED, false)
&& !DeviceFormFactor.isNonMultiDisplayContextOnTablet(
ContextUtils.getApplicationContext())
&& (isDuetTabStripIntegrationAndroidEnabled() || !isTabGroupsAndroidEnabled());
}
/**
* @return The currently enabled bottom toolbar variation.
*/
public static String getBottomToolbarVariation() {
return SharedPreferencesManager.getInstance().readString(
ChromePreferenceKeys.VARIATION_CACHED_BOTTOM_TOOLBAR,
BottomToolbarVariationManager.Variations.NONE);
}
/**
* Set whether the bottom toolbar is enabled for tests. Reset to null at the end of tests.
*/
@VisibleForTesting
public static void setIsBottomToolbarEnabledForTesting(Boolean enabled) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED_BOTTOM_TOOLBAR_ENABLED, enabled);
}
/**
* @return Whether or not the adaptive toolbar is enabled.
*/
public static boolean isAdaptiveToolbarEnabled() {
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_ADAPTIVE_TOOLBAR_ENABLED, true)
&& isBottomToolbarEnabled();
}
/**
* @return Whether or not the labeled bottom toolbar is enabled.
*/
public static boolean isLabeledBottomToolbarEnabled() {
return isFlagEnabled(
ChromePreferenceKeys.FLAGS_CACHED_LABELED_BOTTOM_TOOLBAR_ENABLED, false)
&& isBottomToolbarEnabled();
}
/**
* Cache whether or not night mode is available (i.e. night mode experiment is enabled) so on
* next startup, the value can be made available immediately.
*/
public static void cacheNightModeAvailable() {
boolean available = ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_NIGHT_MODE)
|| (BuildInfo.isAtLeastQ()
&& ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_NIGHT_MODE_FOR_Q));
SharedPreferencesManager.getInstance().writeBoolean(
ChromePreferenceKeys.FLAGS_CACHED_NIGHT_MODE_AVAILABLE, available);
}
/**
* @return Whether or not night mode experiment is enabled (i.e. night mode experiment is
* enabled).
*/
public static boolean isNightModeAvailable() {
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_NIGHT_MODE_AVAILABLE, true);
}
/**
* Toggles whether the night mode experiment is enabled for testing. Should be reset back to
* null after the test has finished.
*/
@VisibleForTesting
public static void setNightModeAvailableForTesting(@Nullable Boolean available) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED_NIGHT_MODE_AVAILABLE, available);
}
/**
* Cache whether or not to default to the light theme when the night mode feature is enabled.
*/
public static void cacheNightModeDefaultToLight() {
// Do not cache on Q (where defaulting to light theme does not apply) or if night mode is
// not enabled.
if (BuildInfo.isAtLeastQ()
|| !ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_NIGHT_MODE)) {
return;
}
String lightModeDefaultParam = "default_light_theme";
boolean lightModeAsDefault = ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
ChromeFeatureList.ANDROID_NIGHT_MODE, lightModeDefaultParam, true);
SharedPreferencesManager.getInstance().writeBoolean(
ChromePreferenceKeys.FLAGS_CACHED_NIGHT_MODE_DEFAULT_TO_LIGHT, lightModeAsDefault);
}
/**
* @return Whether or not to default to the light theme when the night mode feature is enabled.
*/
public static boolean isNightModeDefaultToLight() {
if (BuildInfo.isAtLeastQ()) {
return false;
}
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_NIGHT_MODE_DEFAULT_TO_LIGHT, true);
}
/**
* Toggles whether the night mode experiment is enabled for testing. Should be reset back to
* null after the test has finished.
*/
@VisibleForTesting
public static void setNightModeDefaultToLightForTesting(@Nullable Boolean available) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED_NIGHT_MODE_DEFAULT_TO_LIGHT, available);
}
/**
* Cache whether or not night mode is available for custom tabs (i.e. night mode experiment is
* enabled), so the value is immediately available on next start-up.
*/
public static void cacheNightModeForCustomTabsAvailable() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_NIGHT_MODE_CCT_AVAILABLE,
ChromeFeatureList.ANDROID_NIGHT_MODE_CCT);
}
/**
* @return Whether or not night mode experiment is enabled (i.e. night mode experiment is
* enabled) for custom tabs.
*/
public static boolean isNightModeForCustomTabsAvailable() {
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_NIGHT_MODE_CCT_AVAILABLE, true);
}
/**
* Toggles whether the night mode for custom tabs experiment is enabled. Must only be used for
* testing. Should be reset back to NULL after the test has finished.
*/
public static void setNightModeForCustomTabsAvailableForTesting(Boolean available) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED_NIGHT_MODE_CCT_AVAILABLE, available);
}
/**
* Cache whether or not command line is enabled on non-rooted devices.
*/
private static void cacheCommandLineOnNonRootedEnabled() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_COMMAND_LINE_ON_NON_ROOTED_ENABLED,
ChromeFeatureList.COMMAND_LINE_ON_NON_ROOTED);
}
public static boolean isCommandLineOnNonRootedEnabled() {
return isFlagEnabled(
ChromePreferenceKeys.FLAGS_CACHED_COMMAND_LINE_ON_NON_ROOTED_ENABLED, false);
}
/**
* @return Whether or not the download progress infobar is enabled.
*/
public static boolean isDownloadProgressInfoBarEnabled() {
return ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_PROGRESS_INFOBAR);
}
private static void cacheStartSurfaceEnabled() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_START_SURFACE_ENABLED,
ChromeFeatureList.START_SURFACE_ANDROID);
String feature = ChromeFeatureList.getFieldTrialParamByFeature(
ChromeFeatureList.START_SURFACE_ANDROID, "start_surface_variation");
SharedPreferencesManager.getInstance().writeBoolean(
ChromePreferenceKeys.START_SURFACE_SINGLE_PANE_ENABLED_KEY,
feature.equals("single"));
}
/**
* @return Whether the Start Surface is enabled.
*/
public static boolean isStartSurfaceEnabled() {
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_START_SURFACE_ENABLED, false);
}
private static void cachePaintPreviewTestEnabled() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_PAINT_PREVIEW_TEST_ENABLED_KEY,
ChromeFeatureList.PAINT_PREVIEW_TEST);
}
/**
* @return Whether the Paint Preview tapture test is enabled
*/
public static boolean isPaintPreviewTestEnabled() {
return isFlagEnabled(
ChromePreferenceKeys.FLAGS_CACHED_PAINT_PREVIEW_TEST_ENABLED_KEY, false);
}
@VisibleForTesting
static void cacheNativeTabSwitcherUiFlags() {
if (isEligibleForTabUiExperiments()) {
cacheGridTabSwitcherEnabled();
cacheTabGroupsAndroidEnabled();
cacheDuetTabStripIntegrationAndroidEnabled();
}
}
/**
* @return Whether the Start Surface SinglePane is enabled.
*/
public static boolean isStartSurfaceSinglePaneEnabled() {
return isStartSurfaceEnabled()
&& isFlagEnabled(ChromePreferenceKeys.START_SURFACE_SINGLE_PANE_ENABLED_KEY, false);
}
@VisibleForTesting
static void cacheGridTabSwitcherEnabled() {
SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getInstance();
String featureKey = ChromePreferenceKeys.FLAGS_CACHED_GRID_TAB_SWITCHER_ENABLED;
boolean shouldQueryFeatureFlag = !DeviceClassManager.enableAccessibilityLayout();
if (!shouldQueryFeatureFlag) {
sharedPreferencesManager.writeBoolean(featureKey, false);
return;
}
boolean queriedFlagValue =
ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID);
boolean gridTabSwitcherEnabled =
queriedFlagValue && TabManagementModuleProvider.isTabManagementModuleSupported();
sharedPreferencesManager.writeBoolean(featureKey, gridTabSwitcherEnabled);
}
/**
* @return Whether the Grid Tab Switcher UI is enabled and available for use.
*/
public static boolean isGridTabSwitcherEnabled() {
// TODO(yusufo): AccessibilityLayout check should not be here and the flow should support
// changing that setting while Chrome is alive.
// Having Tab Groups or Start implies Grid Tab Switcher.
return !(isTabGroupsAndroidContinuationChromeFlagEnabled() && SysUtils.isLowEndDevice())
&& isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_GRID_TAB_SWITCHER_ENABLED, false)
|| isTabGroupsAndroidEnabled() || isStartSurfaceEnabled();
}
/**
* Toggles whether the Grid Tab Switcher is enabled for testing. Should be reset back to
* null after the test has finished.
*/
@VisibleForTesting
public static void setGridTabSwitcherEnabledForTesting(@Nullable Boolean enabled) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED_GRID_TAB_SWITCHER_ENABLED, enabled);
}
@VisibleForTesting
static void cacheTabGroupsAndroidEnabled() {
SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getInstance();
String featureKey = ChromePreferenceKeys.FLAGS_CACHED_TAB_GROUPS_ANDROID_ENABLED;
boolean shouldQueryFeatureFlag = !DeviceClassManager.enableAccessibilityLayout();
if (!shouldQueryFeatureFlag) {
sharedPreferencesManager.writeBoolean(featureKey, false);
return;
}
boolean queriedFlagValue =
ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GROUPS_ANDROID);
boolean tabGroupsEnabled =
queriedFlagValue && TabManagementModuleProvider.isTabManagementModuleSupported();
sharedPreferencesManager.writeBoolean(featureKey, tabGroupsEnabled);
}
private static void cacheDuetTabStripIntegrationAndroidEnabled() {
SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getInstance();
String featureKey =
ChromePreferenceKeys.FLAGS_CACHED_DUET_TABSTRIP_INTEGRATION_ANDROID_ENABLED;
boolean shouldQueryFeatureFlag = !DeviceClassManager.enableAccessibilityLayout();
if (!shouldQueryFeatureFlag) {
sharedPreferencesManager.writeBoolean(featureKey, false);
return;
}
boolean queriedFlagValue =
ChromeFeatureList.isEnabled(ChromeFeatureList.DUET_TABSTRIP_INTEGRATION_ANDROID);
boolean duetTabStripIntegrationEnabled =
queriedFlagValue && TabManagementModuleProvider.isTabManagementModuleSupported();
sharedPreferencesManager.writeBoolean(featureKey, duetTabStripIntegrationEnabled);
}
/**
* @return Whether the tab group feature is enabled and available for use.
*/
public static boolean isTabGroupsAndroidEnabled() {
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_TAB_GROUPS_ANDROID_ENABLED, false);
}
/**
* Toggles whether the Tab Group is enabled for testing. Should be reset back to null after the
* test has finished.
*/
@VisibleForTesting
public static void setTabGroupsAndroidEnabledForTesting(@Nullable Boolean available) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED_TAB_GROUPS_ANDROID_ENABLED, available);
}
/**
* Toggles whether the StartSurface is enabled for testing. Should be reset back to null after
* the test has finished.
*/
@VisibleForTesting
public static void setStartSurfaceEnabledForTesting(@Nullable Boolean isEnabled) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED_START_SURFACE_ENABLED, isEnabled);
}
/**
* Toggles whether the Duet-TabStrip integration is enabled for testing. Should be reset back to
* null after the test has finished. Notice that TabGroup should also be turned on in order to
* really get the feature.
*/
@VisibleForTesting
public static void setDuetTabStripIntegrationAndroidEnabledForTesting(
@Nullable Boolean isEnabled) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED_DUET_TABSTRIP_INTEGRATION_ANDROID_ENABLED,
isEnabled);
}
private static boolean isHighEndPhone() {
return !SysUtils.isLowEndDevice()
&& !DeviceFormFactor.isNonMultiDisplayContextOnTablet(
ContextUtils.getApplicationContext());
}
private static boolean isEligibleForTabUiExperiments() {
return (isTabGroupsAndroidContinuationChromeFlagEnabled() || !SysUtils.isLowEndDevice())
&& !DeviceFormFactor.isNonMultiDisplayContextOnTablet(
ContextUtils.getApplicationContext());
}
/**
* @return Whether the tab group ui improvement feature is enabled and available for use.
*/
public static boolean isTabGroupsAndroidUiImprovementsEnabled() {
return isTabGroupsAndroidEnabled()
&& ChromeFeatureList.isEnabled(
ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID);
}
/**
* @return Whether the tab group continuation feature is enabled and available for use.
*/
public static boolean isTabGroupsAndroidContinuationEnabled() {
return isTabGroupsAndroidEnabled() && isTabGroupsAndroidContinuationChromeFlagEnabled();
}
/**
* @return Whether the tab group continuation Chrome flag is enabled.
*/
public static boolean isTabGroupsAndroidContinuationChromeFlagEnabled() {
return ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID);
}
/**
* @return Whether the tab strip and duet integration feature is enabled and available for use.
*/
public static boolean isDuetTabStripIntegrationAndroidEnabled() {
return isTabGroupsAndroidEnabled()
&& isFlagEnabled(
ChromePreferenceKeys.FLAGS_CACHED_DUET_TABSTRIP_INTEGRATION_ANDROID_ENABLED,
false);
}
/**
* @return Whether this device is running Android Go. This is assumed when we're running Android
* O or later and we're on a low-end device.
*/
public static boolean isAndroidGo() {
return SysUtils.isLowEndDevice()
&& android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O;
}
/**
* Cache whether or not bootstrap tasks should be prioritized so on next startup, the value
* can be made available immediately.
*/
public static void cachePrioritizeBootstrapTasks() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_PRIORITIZE_BOOTSTRAP_TASKS,
ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS);
}
/**
* @return Whether or not bootstrap tasks should be prioritized (i.e. bootstrap task
* prioritization experiment is enabled).
*/
public static boolean shouldPrioritizeBootstrapTasks() {
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_PRIORITIZE_BOOTSTRAP_TASKS, true);
}
/**
* Cache whether warming up network service process is enabled, so that the value
* can be made available immediately on next start up.
*/
private static void cacheNetworkServiceWarmUpEnabled() {
SharedPreferencesManager.getInstance().writeBoolean(
ChromePreferenceKeys.FLAGS_CACHED_NETWORK_SERVICE_WARM_UP_ENABLED,
FeatureUtilitiesJni.get().isNetworkServiceWarmUpEnabled());
}
/**
* @return whether warming up network service is enabled.
*/
public static boolean isNetworkServiceWarmUpEnabled() {
return isFlagEnabled(
ChromePreferenceKeys.FLAGS_CACHED_NETWORK_SERVICE_WARM_UP_ENABLED, false);
}
private static void cacheImmersiveUiModeEnabled() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_IMMERSIVE_UI_MODE_ENABLED,
ChromeFeatureList.IMMERSIVE_UI_MODE);
}
/**
* @return Whether immersive ui mode is enabled.
*/
public static boolean isImmersiveUiModeEnabled() {
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED_IMMERSIVE_UI_MODE_ENABLED, false);
}
/**
* Returns whether to use {@link Window#setFormat()} to undo opacity change caused by
* {@link Activity#convertFromTranslucent()}.
*/
public static boolean isSwapPixelFormatToFixConvertFromTranslucentEnabled() {
return SharedPreferencesManager.getInstance().readBoolean(
ChromePreferenceKeys.FLAGS_CACHED_SWAP_PIXEL_FORMAT_TO_FIX_CONVERT_FROM_TRANSLUCENT,
true);
}
public static void cacheSwapPixelFormatToFixConvertFromTranslucentEnabled() {
cacheFlag(
ChromePreferenceKeys.FLAGS_CACHED_SWAP_PIXEL_FORMAT_TO_FIX_CONVERT_FROM_TRANSLUCENT,
ChromeFeatureList.SWAP_PIXEL_FORMAT_TO_FIX_CONVERT_FROM_TRANSLUCENT);
}
/**
* Caches the trial group of the reached code profiler feature to be using on next startup.
*/
private static void cacheReachedCodeProfilerTrialGroup() {
// Make sure that the existing value is saved in a static variable before overwriting it.
if (sReachedCodeProfilerTrialGroup == null) {
getReachedCodeProfilerTrialGroup();
}
SharedPreferencesManager.getInstance().writeString(
ChromePreferenceKeys.REACHED_CODE_PROFILER_GROUP,
FieldTrialList.findFullName(ChromeFeatureList.REACHED_CODE_PROFILER));
}
/**
* @return The trial group of the reached code profiler.
*/
@CalledByNative
public static String getReachedCodeProfilerTrialGroup() {
if (sReachedCodeProfilerTrialGroup == null) {
sReachedCodeProfilerTrialGroup = SharedPreferencesManager.getInstance().readString(
ChromePreferenceKeys.REACHED_CODE_PROFILER_GROUP, "");
}
return sReachedCodeProfilerTrialGroup;
}
/**
* Caches the feature flag for whether we enable the homepage location policy.
*/
private static void cacheHomepageLocationPolicyEnabled() {
cacheFlag(ChromePreferenceKeys.FLAGS_CACHED.createKey(
ChromeFeatureList.HOMEPAGE_LOCATION_POLICY),
ChromeFeatureList.HOMEPAGE_LOCATION_POLICY);
}
/**
* @return True if homepage location policy is supported to be enabled.
*/
public static boolean isHomepageLocationPolicyEnabled() {
return isFlagEnabled(ChromePreferenceKeys.FLAGS_CACHED.createKey(
ChromeFeatureList.HOMEPAGE_LOCATION_POLICY),
false);
}
/**
* Expose an interface to set the homepage policy feature flag to be enabled during tests.
*/
@VisibleForTesting
public static void setHomepageLocationPolicyEnabledForTesting(@Nullable Boolean isEnabled) {
sFlags.put(ChromePreferenceKeys.FLAGS_CACHED.createKey(
ChromeFeatureList.HOMEPAGE_LOCATION_POLICY),
isEnabled);
}
private static void cacheFlag(String preferenceName, String featureName) {
SharedPreferencesManager.getInstance().writeBoolean(
preferenceName, ChromeFeatureList.isEnabled(featureName));
}
private static void cacheVariation(
String preferenceName, String featureName, String variationName) {
SharedPreferencesManager.getInstance().writeString(preferenceName,
ChromeFeatureList.getFieldTrialParamByFeature(featureName, variationName));
}
private static boolean isFlagEnabled(String preferenceName, boolean defaultValue) {
Boolean flag = sFlags.get(preferenceName);
if (flag == null) {
flag = SharedPreferencesManager.getInstance().readBoolean(preferenceName, defaultValue);
sFlags.put(preferenceName, flag);
}
return flag;
}
@VisibleForTesting
public static void resetFlagsForTesting() {
sFlags.clear();
}
@NativeMethods
interface Natives {
void setCustomTabVisible(boolean visible);
void setActivityType(@ActivityType int type);
void setIsInMultiWindowMode(boolean isInMultiWindowMode);
boolean isNetworkServiceWarmUpEnabled();
}
}