Commit 27c67fbb authored by Wenyu Fu's avatar Wenyu Fu Committed by Chromium LUCI CQ

[CCTTosFRE] Cache decision for TosDialogBehavior policy

Store decision if ToS is skipped by policy in shared preference, and
add a singleton helper class to check and refresh the policy value if
necessary.

Change-Id: Ia62622b76207c5ebe7ab226ef3d6f8b18602f488
Bug: 1108582
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2570077Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarSky Malice <skym@chromium.org>
Commit-Queue: Wenyu Fu <wenyufu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835295}
parent 45e9aac0
......@@ -619,6 +619,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java",
"java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupport.java",
"java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFragmentView.java",
"java/src/org/chromium/chrome/browser/firstrun/TosDialogBehaviorSharedPrefInvalidator.java",
"java/src/org/chromium/chrome/browser/flags/ChromeSessionState.java",
"java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java",
"java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java",
......
......@@ -91,6 +91,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationUnitTest.java",
"junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java",
"junit/src/org/chromium/chrome/browser/firstrun/SkipTosDialogPolicyListenerUnitTest.java",
"junit/src/org/chromium/chrome/browser/firstrun/TosDialogBehaviorSharedPrefInvalidatorUnitTest.java",
"junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java",
"junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java",
"junit/src/org/chromium/chrome/browser/gsa/GSAStateUnitTest.java",
......
......@@ -451,7 +451,7 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa
public void exitFirstRun() {
// This is important because the first run, when completed, will re-launch the original
// intent. The re-launched intent will still need to know to avoid the FRE.
FirstRunStatus.setEphemeralSkipFirstRun(true);
FirstRunStatus.setFirstRunSkippedByPolicy(true);
// This pref is written to have a value of true during the FRE's startup. If the user
// presses the accept ToS button, this pref's value is overridden with their choice.
......
......@@ -250,11 +250,10 @@ public abstract class FirstRunFlowSequencer {
// Promo pages are removed, so there is nothing else to show in FRE.
return false;
}
if (FirstRunStatus.isEphemeralSkipFirstRun() && (isCct || preferLightweightFre)) {
if (FirstRunStatus.isFirstRunSkippedByPolicy() && (isCct || preferLightweightFre)) {
// Domain policies may have caused CCTs to skip the FRE. While this needs to be figured
// out at runtime for each app restart, it should apply to all CCTs for the duration of
// the app's lifetime.
// TODO(https://crbug.com/1108582): Replace this with a shared pref.
return false;
}
if (preferLightweightFre
......
......@@ -16,9 +16,6 @@ public class FirstRunStatus {
// Whether the first run flow is triggered in the current browser session.
private static boolean sFirstRunTriggered;
// Whether the first run flow should be skipped for the current browser session.
private static boolean sEphemeralSkipFirstRun;
/** @param triggered whether the first run flow is triggered in the current browser session. */
public static void setFirstRunTriggered(boolean triggered) {
sFirstRunTriggered = triggered;
......@@ -29,23 +26,6 @@ public class FirstRunStatus {
return sFirstRunTriggered;
}
/**
* @param skip Whether the first run flow should be skipped for the current session for app
* entry points that allow for this (e.g. CCTs via Enterprise policy). Not saved to
* durable storage, and will be erased when the process is restarted.
*/
public static void setEphemeralSkipFirstRun(boolean skip) {
sEphemeralSkipFirstRun = skip;
}
/**
* @return Whether the first run flow should be skipped for the current session for app entry
* points that allow for this.
*/
public static boolean isEphemeralSkipFirstRun() {
return sEphemeralSkipFirstRun;
}
/**
* Sets the "main First Run Experience flow complete" preference.
* @param isComplete Whether the main First Run Experience flow is complete
......@@ -102,4 +82,28 @@ public class FirstRunStatus {
return SharedPreferencesManager.getInstance().readBoolean(
ChromePreferenceKeys.FIRST_RUN_LIGHTWEIGHT_FLOW_COMPLETE, false);
}
/**
* Sets the "First Run Experience is skipped by policy" preference. The value of this shared
* preference is used to speed up the decision if first run is needed during start up.
*
* This shared preference could be updated from "true" to "false" if policy is ever unset, but
* not vise versa. Thus, its value could be stale and cannot used to determine if the FRE was
* actually shown in current session.
*
* @param isSkipped Whether the lightweight First Run Experience flow is skipped by policy.
*/
public static void setFirstRunSkippedByPolicy(boolean isSkipped) {
SharedPreferencesManager.getInstance().writeBoolean(
ChromePreferenceKeys.FIRST_RUN_SKIPPED_BY_POLICY, isSkipped);
}
/**
* @return Whether the First Run Experience is skipped by policy.
* @see #setFirstRunSkippedByPolicy
* */
public static boolean isFirstRunSkippedByPolicy() {
return SharedPreferencesManager.getInstance().readBoolean(
ChromePreferenceKeys.FIRST_RUN_SKIPPED_BY_POLICY, false);
}
}
......@@ -257,7 +257,7 @@ public class LightweightFirstRunActivity
mPrivacyDisclaimer.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
mExitFreRunnable = () -> {
FirstRunStatus.setEphemeralSkipFirstRun(true);
FirstRunStatus.setFirstRunSkippedByPolicy(true);
exitLightweightFirstRun();
mExitFreRunnable = null;
};
......
......@@ -26,7 +26,7 @@ import org.chromium.components.policy.PolicyService;
* - Supplies [True] if the ToS dialog is not enabled by policy while device is fully managed;
* - Supplies [False] otherwise.
*/
final class SkipTosDialogPolicyListener implements OneshotSupplier<Boolean> {
class SkipTosDialogPolicyListener implements OneshotSupplier<Boolean> {
/**
* Interface that provides histogram to be recorded when signals are available in this listener.
*/
......@@ -56,9 +56,10 @@ final class SkipTosDialogPolicyListener implements OneshotSupplier<Boolean> {
private final CallbackController mCallbackController;
private final OneshotSupplierImpl<Boolean> mSkipTosDialogPolicySupplier;
private final PolicyLoadListener mPolicyLoadListener;
private final HistogramNameProvider mHistNameProvider;
private final long mObjectCreatedTimeMs;
private final @Nullable HistogramNameProvider mHistNameProvider;
/**
* The value of whether the ToS dialog is enabled on the device. If the value is false, it means
* TosDialogBehavior policy is found and set to SKIP. This can be null when this information
......@@ -80,14 +81,14 @@ final class SkipTosDialogPolicyListener implements OneshotSupplier<Boolean> {
*/
public SkipTosDialogPolicyListener(FirstRunAppRestrictionInfo firstRunAppRestrictionInfo,
OneshotSupplier<PolicyService> policyServiceSupplier, EnterpriseInfo enterpriseInfo,
HistogramNameProvider histogramNameProvider) {
@Nullable HistogramNameProvider histogramNameProvider) {
this(new PolicyLoadListener(firstRunAppRestrictionInfo, policyServiceSupplier),
enterpriseInfo, histogramNameProvider);
}
@VisibleForTesting
SkipTosDialogPolicyListener(PolicyLoadListener policyLoadListener,
EnterpriseInfo enterpriseInfo, HistogramNameProvider histogramNameProvider) {
EnterpriseInfo enterpriseInfo, @Nullable HistogramNameProvider histogramNameProvider) {
mObjectCreatedTimeMs = SystemClock.elapsedRealtime();
mSkipTosDialogPolicySupplier = new OneshotSupplierImpl<>();
mCallbackController = new CallbackController();
......@@ -135,11 +136,13 @@ final class SkipTosDialogPolicyListener implements OneshotSupplier<Boolean> {
mTosDialogEnabled = true;
} else {
mTosDialogEnabled = FirstRunUtils.isCctTosDialogEnabled();
String histogramOnPolicyLoaded =
mHistNameProvider.getOnPolicyAvailableTimeHistogramName();
assert !TextUtils.isEmpty(histogramOnPolicyLoaded);
RecordHistogram.recordTimesHistogram(
histogramOnPolicyLoaded, SystemClock.elapsedRealtime() - mObjectCreatedTimeMs);
if (mHistNameProvider != null) {
String histogramOnPolicyLoaded =
mHistNameProvider.getOnPolicyAvailableTimeHistogramName();
assert !TextUtils.isEmpty(histogramOnPolicyLoaded);
RecordHistogram.recordTimesHistogram(histogramOnPolicyLoaded,
SystemClock.elapsedRealtime() - mObjectCreatedTimeMs);
}
}
setSupplierIfDecidable();
......@@ -149,11 +152,13 @@ final class SkipTosDialogPolicyListener implements OneshotSupplier<Boolean> {
if (mIsDeviceOwned != null) return;
mIsDeviceOwned = ownedState != null && ownedState.mDeviceOwned;
String histogramOnEnterpriseInfoLoaded =
mHistNameProvider.getOnDeviceOwnedDetectedTimeHistogramName();
assert !TextUtils.isEmpty(histogramOnEnterpriseInfoLoaded);
RecordHistogram.recordTimesHistogram(histogramOnEnterpriseInfoLoaded,
SystemClock.elapsedRealtime() - mObjectCreatedTimeMs);
if (mHistNameProvider != null) {
String histogramOnEnterpriseInfoLoaded =
mHistNameProvider.getOnDeviceOwnedDetectedTimeHistogramName();
assert !TextUtils.isEmpty(histogramOnEnterpriseInfoLoaded);
RecordHistogram.recordTimesHistogram(histogramOnEnterpriseInfoLoaded,
SystemClock.elapsedRealtime() - mObjectCreatedTimeMs);
}
setSupplierIfDecidable();
}
......
......@@ -172,8 +172,6 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
}
private void exitCctFirstRun(boolean shiftA11yFocus) {
// TODO(crbug.com/1108582): Save a shared pref indicating Enterprise CCT FRE is complete,
// and skip waiting for future cold starts.
Log.d(TAG, "TosAndUmaFirstRunFragmentWithEnterpriseSupport finished.");
mPrivacyDisclaimer.setVisibility(View.VISIBLE);
......
// Copyright 2020 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.firstrun;
import android.os.SystemClock;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils;
import org.chromium.base.supplier.OneshotSupplierImpl;
import org.chromium.chrome.browser.policy.EnterpriseInfo;
import org.chromium.chrome.browser.policy.PolicyServiceFactory;
import org.chromium.components.policy.PolicyService;
/**
* Class that used to refresh "If the ToS was and should be skipped by policy TosDialogBehavior".
*
* Once FRE is skipped because of the enterprise policy TosDialogBehavior, this information is
* stored in {@link ChromePreferenceKeys#FIRST_RUN_SKIPPED_BY_POLICY}. The FRE will be completely
* avoided when this pref is true. This class checks if the enterprise policy is ever reset such
* that the FRE should be run, and will clear the shared pref.
*/
public class TosDialogBehaviorSharedPrefInvalidator {
private static final String TAG = "TosPolicyStatus";
private final SkipTosDialogPolicyListener mPolicyListener;
private final FirstRunAppRestrictionInfo mAppRestrictionInfo;
private final long mTimeObjectCreated;
/**
* Refresh boolean value "If the ToS was and should be skipped by policy TosDialogBehavior"
* that is stored in the shared preference. If the ToS was not skipped, do nothing.
*/
public static void refreshSharedPreferenceIfTosSkipped() {
ThreadUtils.assertOnUiThread();
if (!FirstRunStatus.isFirstRunSkippedByPolicy()) return;
FirstRunAppRestrictionInfo appRestrictionInfo =
FirstRunAppRestrictionInfo.takeMaybeInitialized();
OneshotSupplierImpl<PolicyService> policyServiceSupplier = new OneshotSupplierImpl<>();
policyServiceSupplier.set(PolicyServiceFactory.getGlobalPolicyService());
SkipTosDialogPolicyListener policyListener = new SkipTosDialogPolicyListener(
appRestrictionInfo, policyServiceSupplier, EnterpriseInfo.getInstance(), null);
new TosDialogBehaviorSharedPrefInvalidator(policyListener, appRestrictionInfo);
}
@VisibleForTesting
TosDialogBehaviorSharedPrefInvalidator(
SkipTosDialogPolicyListener listener, FirstRunAppRestrictionInfo appRestrictionInfo) {
mTimeObjectCreated = SystemClock.elapsedRealtime();
mAppRestrictionInfo = appRestrictionInfo;
mPolicyListener = listener;
mPolicyListener.onAvailable(this::onPolicyAvailable);
}
private void onPolicyAvailable(boolean shouldSkipTosDialog) {
long duration = SystemClock.elapsedRealtime() - mTimeObjectCreated;
Log.d(TAG, "Task finished. Duration: [%d], result: [%s]", duration, shouldSkipTosDialog);
if (!shouldSkipTosDialog) FirstRunStatus.setFirstRunSkippedByPolicy(false);
mAppRestrictionInfo.destroy();
mPolicyListener.destroy();
}
}
......@@ -50,6 +50,7 @@ import org.chromium.chrome.browser.download.DownloadManagerService;
import org.chromium.chrome.browser.download.OfflineContentAvailabilityStatusProvider;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.firstrun.ForcedSigninProcessor;
import org.chromium.chrome.browser.firstrun.TosDialogBehaviorSharedPrefInvalidator;
import org.chromium.chrome.browser.flags.CachedFeatureFlags;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.history.HistoryDeletionBridge;
......@@ -439,6 +440,8 @@ public class ProcessInitializationHandler {
() -> EnterpriseInfo.getInstance().logDeviceEnterpriseInfo());
deferredStartupHandler.addDeferredTask(
() -> VideoTutorialShareHelper.saveUrlsToSharedPrefs());
deferredStartupHandler.addDeferredTask(
() -> TosDialogBehaviorSharedPrefInvalidator.refreshSharedPreferenceIfTosSkipped());
}
private void initChannelsAsync() {
......
......@@ -36,8 +36,10 @@ import org.chromium.base.CollectionUtil;
import org.chromium.base.task.PostTask;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.ScalableTimeout;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.DeferredStartupHandler;
import org.chromium.chrome.browser.customtabs.CustomTabActivity;
import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
import org.chromium.chrome.browser.document.ChromeLauncherActivity;
......@@ -90,6 +92,7 @@ public class FirstRunIntegrationTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
FirstRunStatus.setFirstRunSkippedByPolicy(false);
FirstRunActivity.setObserverForTest(mTestObserver);
ToSAndUMAFirstRunFragment.setShowUmaCheckBoxForTesting(true);
......@@ -104,6 +107,7 @@ public class FirstRunIntegrationTest {
@After
public void tearDown() {
FirstRunStatus.setFirstRunSkippedByPolicy(false);
FirstRunAppRestrictionInfo.setInitializedInstanceForTest(null);
ToSAndUMAFirstRunFragment.setShowUmaCheckBoxForTesting(false);
EnterpriseInfo.setInstanceForTest(null);
......@@ -311,7 +315,26 @@ public class FirstRunIntegrationTest {
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
Assert.assertTrue(
"FRE should be skipped for CCT.", FirstRunStatus.isEphemeralSkipFirstRun());
"FRE should be skipped for CCT.", FirstRunStatus.isFirstRunSkippedByPolicy());
}
@Test
@MediumTest
public void testFirstRunSkippedSharedPreferenceRefresh() {
// Set first run was previous skipped by policy in shared preference, then refresh shared
// preference value, since there's no policy set in this test case.
FirstRunStatus.setFirstRunSkippedByPolicy(true);
DeferredStartupHandler.setExpectingActivityStartupForTesting();
Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(mContext, "about:blank");
mContext.startActivity(intent);
CustomTabActivity activity = waitForActivity(CustomTabActivity.class);
CriteriaHelper.pollUiThread(() -> activity.didFinishNativeInitialization());
Assert.assertTrue("Deferred startup never completed",
DeferredStartupHandler.waitForDeferredStartupCompleteForTesting(
ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL)));
CriteriaHelper.pollUiThread(() -> FirstRunStatus.isFirstRunSkippedByPolicy());
}
@Test
......@@ -333,7 +356,7 @@ public class FirstRunIntegrationTest {
// A page skip should happen, while we are still staying at FRE.
mTestObserver.jumpToPageCallback.waitForCallback("Welcome page should be skipped.", 0);
Assert.assertFalse(
"FRE should not be skipped for CCT.", FirstRunStatus.isEphemeralSkipFirstRun());
"FRE should not be skipped for CCT.", FirstRunStatus.isFirstRunSkippedByPolicy());
Assert.assertFalse(
"FreActivity should still be alive.", freActivity.isActivityFinishingOrDestroyed());
}
......
......@@ -299,7 +299,7 @@ public class SkipTosDialogPolicyListenerUnitTest {
}
@Test
public void testUpdateHistogramNameProvider() {
public void testHistogramNameProvider_UpdateProvider() {
// Update the names for mHistogramNameProvider and test if the old hists are not recorded.
String newHistogramForEnterprise = "another.histogram.enterprise";
String newHistogramForPolicy = "another.histogram.policy";
......@@ -323,6 +323,20 @@ public class SkipTosDialogPolicyListenerUnitTest {
RecordHistogram.getHistogramTotalCountForTesting(newHistogramForPolicy));
}
@Test
public void testHistogramNameProvider_NoProvider() {
buildNewSkipTosDialogPolicyListenerWithHistogram(false);
setDeviceFullyManaged(true);
Assert.assertEquals("No histogram for EnterpriseInfo should not be recorded.", 0,
RecordHistogram.getHistogramTotalCountForTesting(HIST_IS_DEVICE_OWNED_DETECTED));
mPolicyLoadListenerCallback.onResult(true);
Assert.assertEquals("No histogram for Policy should not be recorded.", 0,
RecordHistogram.getHistogramTotalCountForTesting(
HIST_POLICY_LOAD_LISTENER_AVAILABLE));
}
private void assertTosDialogEnabled() {
Assert.assertFalse("ToS dialog should be enabled.", mSkipTosDialogPolicyListener.get());
Mockito.verify(mTosDialogCallback).onResult(false);
......@@ -365,8 +379,12 @@ public class SkipTosDialogPolicyListenerUnitTest {
}
private void buildNewSkipTosDialogPolicyListener() {
mSkipTosDialogPolicyListener = new SkipTosDialogPolicyListener(
mMockPolicyLoadListener, mMockEnterpriseInfo, mHistogramNameProvider);
buildNewSkipTosDialogPolicyListenerWithHistogram(true);
}
private void buildNewSkipTosDialogPolicyListenerWithHistogram(boolean reportHistogram) {
mSkipTosDialogPolicyListener = new SkipTosDialogPolicyListener(mMockPolicyLoadListener,
mMockEnterpriseInfo, reportHistogram ? mHistogramNameProvider : null);
mSkipTosDialogPolicyListener.onAvailable(mTosDialogCallback);
}
......
// Copyright 2020 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.firstrun;
import static org.mockito.ArgumentMatchers.any;
import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.annotation.Config;
import org.chromium.base.Callback;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.policy.PolicyServiceFactory;
import org.chromium.components.policy.PolicyService;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
/** Unit test for {@link TosDialogBehaviorSharedPrefInvalidator}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class TosDialogBehaviorSharedPrefInvalidatorUnitTest {
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
public FirstRunAppRestrictionInfo mMockAppRestrictionInfo;
@Mock
public PolicyService mMockPolicyService;
@Mock
public SkipTosDialogPolicyListener mMockPolicyListener;
private TosDialogBehaviorSharedPrefInvalidator mStatusHelper;
private Callback<Boolean> mOnPolicyAvailableCallback;
@Before
public void setUp() {
Mockito.doAnswer(invocation -> {
mOnPolicyAvailableCallback = invocation.getArgument(0);
return null;
})
.when(mMockPolicyListener)
.onAvailable(any());
Mockito.doReturn(null).when(mMockPolicyListener).get();
FirstRunStatus.setFirstRunSkippedByPolicy(false);
FirstRunAppRestrictionInfo.setInitializedInstanceForTest(mMockAppRestrictionInfo);
PolicyServiceFactory.setPolicyServiceForTest(mMockPolicyService);
}
@After
public void tearDown() {
FirstRunStatus.setFirstRunSkippedByPolicy(false);
FirstRunAppRestrictionInfo.setInitializedInstanceForTest(null);
PolicyServiceFactory.setPolicyServiceForTest(null);
}
@Test
@SmallTest
public void testSkipNotTriggered() {
TestThreadUtils.runOnUiThreadBlocking(
TosDialogBehaviorSharedPrefInvalidator::refreshSharedPreferenceIfTosSkipped);
Mockito.verify(mMockAppRestrictionInfo, Mockito.never()).getHasAppRestriction(any());
Mockito.verify(mMockPolicyService, Mockito.never()).addObserver(any());
}
@Test
@SmallTest
public void testSkipTriggered() {
FirstRunStatus.setFirstRunSkippedByPolicy(true);
TestThreadUtils.runOnUiThreadBlocking(
TosDialogBehaviorSharedPrefInvalidator::refreshSharedPreferenceIfTosSkipped);
Mockito.verify(mMockAppRestrictionInfo).getHasAppRestriction(any());
Mockito.verify(mMockPolicyService).addObserver(any());
}
@Test
@SmallTest
public void testRefreshTriggered_NotSkippedByPolicy() {
FirstRunStatus.setFirstRunSkippedByPolicy(true);
launchSharedPrefInvalidator();
// Assuming SkipTosDialogPolicyListener supplied with "False".
mOnPolicyAvailableCallback.onResult(false);
Assert.assertFalse("Value for #isFirstRunSkippedByPolicy should be set to false.",
FirstRunStatus.isFirstRunSkippedByPolicy());
Mockito.verify(mMockPolicyListener).destroy();
Mockito.verify(mMockAppRestrictionInfo).destroy();
}
/**
* Test to verify if #mOnPolicyAvailableCallback in TosDialogBehaviorSharedPrefInvalidator is
* doing correct task.
*
* Noting that shared preference only controls whether a TosDialogBehaviorSharedPrefInvalidator
* will be created or not. Once an instance is created, it runs regardless the value of
* FirstRunStatus#isFirstRunSkippedByPolicy.
*/
@Test
@SmallTest
public void testRefreshTriggered_RemainSkippedByPolicy() {
FirstRunStatus.setFirstRunSkippedByPolicy(true);
launchSharedPrefInvalidator();
// Assuming SkipTosDialogPolicyListener supplied with "True".
mOnPolicyAvailableCallback.onResult(true);
Assert.assertTrue("Value for #isFirstRunSkippedByPolicy should stay true.",
FirstRunStatus.isFirstRunSkippedByPolicy());
Mockito.verify(mMockPolicyListener).destroy();
Mockito.verify(mMockAppRestrictionInfo).destroy();
}
private void launchSharedPrefInvalidator() {
new TosDialogBehaviorSharedPrefInvalidator(mMockPolicyListener, mMockAppRestrictionInfo);
Assert.assertNotNull("Callback should registered for SkipTosDialogPolicyListener.",
mOnPolicyAvailableCallback);
}
}
......@@ -352,6 +352,7 @@ public final class ChromePreferenceKeys {
public static final String FIRST_RUN_FLOW_SIGNIN_SETUP = "first_run_signin_setup";
public static final String FIRST_RUN_LIGHTWEIGHT_FLOW_COMPLETE = "lightweight_first_run_flow";
public static final String FIRST_RUN_SKIP_WELCOME_PAGE = "skip_welcome_page";
public static final String FIRST_RUN_SKIPPED_BY_POLICY = "Chrome.FirstRun.SkippedByPolicy";
/**
* Cached feature flags generated by CachedFeatureFlags use this prefix.
......@@ -835,6 +836,7 @@ public final class ChromePreferenceKeys {
EXPLORE_OFFLINE_CONTENT_AVAILABILITY_STATUS,
FEED_ARTICLES_LIST_VISIBLE,
FEED_PLACEHOLDER_DENSE,
FIRST_RUN_SKIPPED_BY_POLICY,
FLAGS_CACHED.pattern(),
FLAGS_FIELD_TRIAL_PARAM_CACHED.pattern(),
HOMEPAGE_LOCATION_POLICY,
......
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