blob: a7da32531a00de4036c67d03b7523b1cb29d2e91 [file] [log] [blame]
// 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.hamcrest.Matchers.is;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.view.View;
import android.widget.CheckBox;
import androidx.annotation.IntDef;
import androidx.test.filters.SmallTest;
import org.hamcrest.Matchers;
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.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.chromium.base.Callback;
import org.chromium.base.CommandLine;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
import org.chromium.chrome.browser.enterprise.util.EnterpriseInfo;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.init.BrowserParts;
import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
import org.chromium.chrome.browser.policy.PolicyServiceFactory;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.ChromeRenderTestRule;
import org.chromium.components.policy.PolicyService;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.test.util.DisableAnimationsTestRule;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
/**
* Test for first run activity and {@link TosAndUmaFirstRunFragmentWithEnterpriseSupport}.
* For the outside signals that used in this test so that the verification is focusing on the
* workflow and UI transition.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
public class TosAndUmaFirstRunFragmentWithEnterpriseSupportTest {
@IntDef({FragmentState.LOADING, FragmentState.NO_POLICY, FragmentState.HAS_POLICY,
FragmentState.WAITING_UNTIL_NEXT_PAGE})
@Retention(RetentionPolicy.SOURCE)
@interface FragmentState {
int LOADING = 0;
int NO_POLICY = 1;
int HAS_POLICY = 2;
int WAITING_UNTIL_NEXT_PAGE = 3;
}
@IntDef({SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.FASTER,
SpeedComparedToInflation.SLOWER})
@Retention(RetentionPolicy.SOURCE)
@interface SpeedComparedToInflation {
int NOT_RECORDED = 0;
int FASTER = 1;
int SLOWER = 2;
}
private static final int RENDER_TEST_REVISION = 2;
private static final String RENDER_TEST_REVISION_DESCRIPTION =
"Change the button padding and font family.";
@Rule
public DisableAnimationsTestRule mDisableAnimationsTestRule = new DisableAnimationsTestRule();
@Rule
public ChromeRenderTestRule mRenderTestRule =
ChromeRenderTestRule.Builder.withPublicCorpus()
.setRevision(RENDER_TEST_REVISION)
.setDescription(RENDER_TEST_REVISION_DESCRIPTION)
.build();
@Mock
public FirstRunAppRestrictionInfo mMockAppRestrictionInfo;
@Mock
public PolicyService mPolicyService;
@Mock
public FirstRunUtils.Natives mFirstRunUtils;
@Mock
public EnterpriseInfo mMockEnterpriseInfo;
@Spy
public ChromeBrowserInitializer mInitializer;
@Captor
public ArgumentCaptor<BrowserParts> mBrowserParts;
private FirstRunActivity mActivity;
private final List<PolicyService.Observer> mPolicyServiceObservers = new ArrayList<>();
private final List<Callback<Boolean>> mAppRestrictionsCallbacks = new ArrayList<>();
private final List<Callback<Long>> mAppRestrictionsDurationCallbacks = new ArrayList<>();
private final List<Callback<EnterpriseInfo.OwnedState>> mOwnedStateCallbacks =
new ArrayList<>();
private final CallbackHelper mAcceptTosCallbackHelper = new CallbackHelper();
private CallbackHelper mOnNativeInitializedHelper = new CallbackHelper();
private int mExitCount;
private View mTosText;
private View mAcceptButton;
private View mLowerSpinner;
private View mCenterSpinner;
private View mPrivacyDisclaimer;
private CheckBox mUmaCheckBox;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Assert.assertFalse(
CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE));
Mockito.doNothing()
.when(mInitializer)
.handlePostNativeStartup(anyBoolean(), any(BrowserParts.class));
ChromeBrowserInitializer.setForTesting(mInitializer);
FirstRunAppRestrictionInfo.setInitializedInstanceForTest(mMockAppRestrictionInfo);
ToSAndUMAFirstRunFragment.setShowUmaCheckBoxForTesting(true);
PolicyServiceFactory.setPolicyServiceForTest(mPolicyService);
FirstRunUtils.setDisableDelayOnExitFreForTest(true);
FirstRunUtilsJni.TEST_HOOKS.setInstanceForTesting(mFirstRunUtils);
EnterpriseInfo.setInstanceForTest(mMockEnterpriseInfo);
setAppRestrictionsMockNotInitialized();
setPolicyServiceMockNotInitialized();
setEnterpriseInfoNotInitialized();
// TODO(https://crbug.com/1113229): Rework this to not depend on {@link FirstRunActivity}
// implementation details.
mExitCount = 0;
FirstRunActivity.setObserverForTest(new FirstRunActivity.FirstRunActivityObserver() {
@Override
public void onCreatePostNativeAndPoliciesPageSequence(
FirstRunActivity caller, Bundle freProperties) {}
@Override
public void onAcceptTermsOfService(FirstRunActivity caller) {
mAcceptTosCallbackHelper.notifyCalled();
}
@Override
public void onJumpToPage(FirstRunActivity caller, int position) {}
@Override
public void onUpdateCachedEngineName(FirstRunActivity caller) {}
@Override
public void onAbortFirstRunExperience(FirstRunActivity caller) {}
@Override
public void onExitFirstRun(FirstRunActivity caller) {
mExitCount++;
}
});
ToSAndUMAFirstRunFragment.setObserverForTesting(new ToSAndUMAFirstRunFragment.Observer() {
@Override
public void onNativeInitialized() {
mOnNativeInitializedHelper.notifyCalled();
}
});
}
@After
public void tearDown() {
FirstRunAppRestrictionInfo.setInitializedInstanceForTest(null);
ToSAndUMAFirstRunFragment.setShowUmaCheckBoxForTesting(false);
TosAndUmaFirstRunFragmentWithEnterpriseSupport.setOverrideOnExitFreRunnableForTest(null);
PolicyServiceFactory.setPolicyServiceForTest(null);
FirstRunUtils.setDisableDelayOnExitFreForTest(false);
FirstRunUtilsJni.TEST_HOOKS.setInstanceForTesting(mFirstRunUtils);
EnterpriseInfo.setInstanceForTest(null);
SharedPreferencesManager.getInstance().writeBoolean(
ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, false);
if (mActivity != null) mActivity.finish();
}
@Test
@SmallTest
public void testNoRestriction() throws Exception {
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
setAppRestrictionsMockInitialized(false);
assertUIState(FragmentState.NO_POLICY);
assertHistograms(true, SpeedComparedToInflation.SLOWER,
SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.NOT_RECORDED);
assertPolicyServiceInitDelayAfterNative(true, false);
// Try to accept ToS.
setMetricsReportDisabled();
TestThreadUtils.runOnUiThreadBlocking((Runnable) mAcceptButton::performClick);
Assert.assertTrue("Crash report should be enabled.",
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
}
@Test
@SmallTest
public void testNoRestriction_AcceptBeforeNative() throws Exception {
launchFirstRunThroughCustomTabPreNative();
assertUIState(FragmentState.LOADING);
setAppRestrictionsMockInitialized(false);
assertUIState(FragmentState.NO_POLICY);
// Try to accept ToS.
setMetricsReportDisabled();
TestThreadUtils.runOnUiThreadBlocking((Runnable) mAcceptButton::performClick);
assertUIState(FragmentState.WAITING_UNTIL_NEXT_PAGE);
Assert.assertFalse("Crash report should not be enabled before native initialized.",
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
// ToS should be accepted when native is initialized.
startNativeInitializationAndWait();
assertHistograms(true, SpeedComparedToInflation.SLOWER,
SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.NOT_RECORDED);
assertPolicyServiceInitDelayAfterNative(false, false);
String histogram = "MobileFre.TosFragment.SpinnerVisibleDuration";
Assert.assertEquals(String.format("Histogram <%s> should be recorded.", histogram), 1,
RecordHistogram.getHistogramTotalCountForTesting(histogram));
Assert.assertTrue("Crash report should be enabled.",
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
}
@Test
@SmallTest
public void testNoRestriction_BeforeInflation() throws Exception {
setAppRestrictionsMockInitialized(false);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.NO_POLICY);
assertHistograms(false, SpeedComparedToInflation.FASTER,
SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.NOT_RECORDED);
assertPolicyServiceInitDelayAfterNative(false, false);
}
@Test
@SmallTest
// TODO(crbug.com/1120859): Test the policy check when native initializes before inflation.
// This will be possible when FragmentScenario is available.
public void testDialogEnabled() throws Exception {
setAppRestrictionsMockInitialized(true);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
setPolicyServiceMockInitializedWithDialogEnabled(true);
assertUIState(FragmentState.NO_POLICY);
assertHistograms(true, SpeedComparedToInflation.FASTER,
SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.SLOWER);
assertPolicyServiceInitDelayAfterNative(true, true);
// Try to accept ToS.
TestThreadUtils.runOnUiThreadBlocking((Runnable) mAcceptButton::performClick);
Assert.assertTrue("Crash report should be enabled.",
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
}
@Test
@SmallTest
public void testDialogEnabled_BeforeAppRestrictions() throws Exception {
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
// When policy is loaded on fully managed device, we don't need app restriction.
setPolicyServiceMockInitializedWithDialogEnabled(true);
assertUIState(FragmentState.NO_POLICY);
assertHistograms(true, SpeedComparedToInflation.NOT_RECORDED,
SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.SLOWER);
assertPolicyServiceInitDelayAfterNative(true, true);
}
@Test
@SmallTest
public void testNotOwnedDevice() throws Exception {
setAppRestrictionsMockInitialized(true);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
setEnterpriseInfoInitializedWithDeviceOwner(false);
assertUIState(FragmentState.NO_POLICY);
assertHistograms(true, SpeedComparedToInflation.FASTER, SpeedComparedToInflation.SLOWER,
SpeedComparedToInflation.NOT_RECORDED);
assertPolicyServiceInitDelayAfterNative(false, false);
}
@Test
@SmallTest
public void testNotOwnedDevice_AcceptBeforePolicy() throws Exception {
setAppRestrictionsMockInitialized(true);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
setEnterpriseInfoInitializedWithDeviceOwner(false);
assertUIState(FragmentState.NO_POLICY);
// Try to accept Tos.
setMetricsReportDisabled();
TestThreadUtils.runOnUiThreadBlocking((Runnable) mAcceptButton::performClick);
assertUIState(FragmentState.WAITING_UNTIL_NEXT_PAGE);
setPolicyServiceMockInitializedWithDialogEnabled(false);
CriteriaHelper.pollUiThread(()
-> PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
String histogram = "MobileFre.TosFragment.SpinnerVisibleDuration";
Assert.assertEquals(String.format("Histogram <%s> should be recorded.", histogram), 1,
RecordHistogram.getHistogramTotalCountForTesting(histogram));
assertHistograms(true, SpeedComparedToInflation.FASTER, SpeedComparedToInflation.SLOWER,
SpeedComparedToInflation.SLOWER);
assertPolicyServiceInitDelayAfterNative(true, true);
}
@Test
@SmallTest
public void testNotOwnedDevice_BeforeInflation() throws Exception {
setAppRestrictionsMockInitialized(true);
setEnterpriseInfoInitializedWithDeviceOwner(false);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.NO_POLICY);
assertHistograms(false, SpeedComparedToInflation.FASTER, SpeedComparedToInflation.FASTER,
SpeedComparedToInflation.NOT_RECORDED);
assertPolicyServiceInitDelayAfterNative(false, false);
}
@Test
@SmallTest
public void testOwnedDevice_NoRestriction() throws Exception {
setEnterpriseInfoInitializedWithDeviceOwner(true);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
setAppRestrictionsMockInitialized(false);
assertUIState(FragmentState.NO_POLICY);
assertHistograms(true, SpeedComparedToInflation.SLOWER, SpeedComparedToInflation.FASTER,
SpeedComparedToInflation.NOT_RECORDED);
assertPolicyServiceInitDelayAfterNative(true, false);
}
@Test
@SmallTest
public void testOwnedDevice_NoPolicy() throws Exception {
setEnterpriseInfoInitializedWithDeviceOwner(true);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
setAppRestrictionsMockInitialized(true);
assertUIState(FragmentState.LOADING);
setPolicyServiceMockInitializedWithDialogEnabled(true);
assertUIState(FragmentState.NO_POLICY);
assertHistograms(true, SpeedComparedToInflation.SLOWER, SpeedComparedToInflation.FASTER,
SpeedComparedToInflation.SLOWER);
assertPolicyServiceInitDelayAfterNative(true, true);
}
@Test
@SmallTest
public void testSkip_DeviceOwnedThenDialogPolicy() throws Exception {
setAppRestrictionsMockInitialized(true);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
setEnterpriseInfoInitializedWithDeviceOwner(true);
assertUIState(FragmentState.LOADING);
setPolicyServiceMockInitializedWithDialogEnabled(false);
assertUIState(FragmentState.HAS_POLICY);
assertHistograms(true, SpeedComparedToInflation.FASTER, SpeedComparedToInflation.SLOWER,
SpeedComparedToInflation.SLOWER);
assertPolicyServiceInitDelayAfterNative(true, true);
Assert.assertFalse("Crash report should not be enabled.",
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
}
@Test
@SmallTest
public void testSkip_DialogPolicyThenDeviceOwned() throws Exception {
setAppRestrictionsMockInitialized(true);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
setPolicyServiceMockInitializedWithDialogEnabled(false);
assertUIState(FragmentState.LOADING);
setEnterpriseInfoInitializedWithDeviceOwner(true);
assertUIState(FragmentState.HAS_POLICY);
assertHistograms(true, SpeedComparedToInflation.FASTER, SpeedComparedToInflation.SLOWER,
SpeedComparedToInflation.SLOWER);
assertPolicyServiceInitDelayAfterNative(true, true);
Assert.assertFalse("Crash report should not be enabled.",
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
}
@Test
@SmallTest
public void testSkip_LateAppRestrictions() throws Exception {
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
setPolicyServiceMockInitializedWithDialogEnabled(false);
assertUIState(FragmentState.LOADING);
// Skip should happen without app restrictions being completed.
setEnterpriseInfoInitializedWithDeviceOwner(true);
assertUIState(FragmentState.HAS_POLICY);
assertHistograms(true, SpeedComparedToInflation.NOT_RECORDED,
SpeedComparedToInflation.SLOWER, SpeedComparedToInflation.SLOWER);
assertPolicyServiceInitDelayAfterNative(true, true);
// assertUIState will verify that exit was not called a second time.
setAppRestrictionsMockInitialized(true);
assertUIState(FragmentState.HAS_POLICY);
assertHistograms(true, SpeedComparedToInflation.SLOWER, SpeedComparedToInflation.SLOWER,
SpeedComparedToInflation.SLOWER);
Assert.assertFalse("Crash report should not be enabled.",
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
}
@Test
@SmallTest
public void testNullOwnedState() throws Exception {
setAppRestrictionsMockInitialized(true);
setPolicyServiceMockInitializedWithDialogEnabled(false);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
// Null means loading checking if the device is owned failed. This should be treated the
// same as not being owned, and no skipping should occur.
setEnterpriseInfoInitializedWithOwnedState(null);
assertUIState(FragmentState.NO_POLICY);
}
@Test
@SmallTest
@DisabledTest(message = "Flaky test - see: https://crbug.com/1171147")
public void testAcceptTosWithoutCrashUpload() throws Exception {
setAppRestrictionsMockInitialized(true);
setEnterpriseInfoInitializedWithDeviceOwner(true);
setPolicyServiceMockInitializedWithDialogEnabled(true);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.NO_POLICY);
// Accept ToS without check on UMA.
TestThreadUtils.runOnUiThreadBlocking(() -> {
mUmaCheckBox.setChecked(false);
mAcceptButton.performClick();
});
mAcceptTosCallbackHelper.waitForCallback("Accept Tos is never called.", 0);
Assert.assertFalse("Crash report should not be enabled.",
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
}
@Test
@SmallTest
@Feature({"RenderTest", "FirstRun"})
public void testRender() throws Exception {
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
// Clear the focus on view to avoid unexpected highlight on background.
View tosAndUmaFragment =
mActivity.getSupportFragmentManager().getFragments().get(0).getView();
Assert.assertNotNull(tosAndUmaFragment);
TestThreadUtils.runOnUiThreadBlocking(tosAndUmaFragment::clearFocus);
renderWithPortraitAndLandscape(tosAndUmaFragment, "fre_tosanduma_loading");
setAppRestrictionsMockInitialized(false);
assertUIState(FragmentState.NO_POLICY);
renderWithPortraitAndLandscape(tosAndUmaFragment, "fre_tosanduma_nopolicy");
}
@Test
@SmallTest
@Feature({"RenderTest", "FirstRun"})
public void testRenderWithPolicy() throws Exception {
final CallbackHelper onExitFreCallback = new CallbackHelper();
TosAndUmaFirstRunFragmentWithEnterpriseSupport.setOverrideOnExitFreRunnableForTest(
onExitFreCallback::notifyCalled);
setAppRestrictionsMockInitialized(true);
setEnterpriseInfoInitializedWithDeviceOwner(true);
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
// Clear the focus on view to avoid unexpected highlight on background.
View tosAndUmaFragment =
mActivity.getSupportFragmentManager().getFragments().get(0).getView();
Assert.assertNotNull(tosAndUmaFragment);
TestThreadUtils.runOnUiThreadBlocking(tosAndUmaFragment::clearFocus);
setPolicyServiceMockInitializedWithDialogEnabled(false);
onExitFreCallback.waitForFirst("OnExitFreCallback is never invoked.");
Assert.assertEquals("Privacy disclaimer is not visible", mPrivacyDisclaimer.getVisibility(),
View.VISIBLE);
renderWithPortraitAndLandscape(tosAndUmaFragment, "fre_tosanduma_withpolicy");
}
private void launchFirstRunThroughCustomTab() throws TimeoutException {
launchFirstRunThroughCustomTabPreNative();
startNativeInitializationAndWait();
}
/**
* Launch chrome through custom tab and trigger first run.
*/
private void launchFirstRunThroughCustomTabPreNative() {
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
final Context context = instrumentation.getTargetContext();
// Create an Intent that causes Chrome to run.
Intent intent =
CustomTabsTestUtils.createMinimalCustomTabIntent(context, "https://test.com");
// Start the FRE.
final ActivityMonitor freMonitor =
new ActivityMonitor(FirstRunActivity.class.getName(), null, false);
instrumentation.addMonitor(freMonitor);
// As we want to test on FirstRunActivity, which starts its lifecycle *before*
// CustomTabActivity fully initialized, we'll launch the activity without the help of
// CustomTabActivityTestRule (which waits until any tab is created).
context.startActivity(intent);
// Wait for the FRE to be ready to use.
Activity activity =
freMonitor.waitForActivityWithTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL);
instrumentation.removeMonitor(freMonitor);
mActivity = (FirstRunActivity) activity;
CriteriaHelper.pollUiThread(
() -> mActivity.getSupportFragmentManager().getFragments().size() > 0);
mTosText = mActivity.findViewById(R.id.tos_and_privacy);
mUmaCheckBox = mActivity.findViewById(R.id.send_report_checkbox);
mAcceptButton = mActivity.findViewById(R.id.terms_accept);
mLowerSpinner = mActivity.findViewById(R.id.progress_spinner);
mCenterSpinner = mActivity.findViewById(R.id.progress_spinner_large);
mPrivacyDisclaimer = mActivity.findViewById(R.id.privacy_disclaimer);
}
private void assertUIState(@FragmentState int fragmentState) {
int tosVisibility = (fragmentState == FragmentState.NO_POLICY) ? View.VISIBLE : View.GONE;
int spinnerVisibility = (fragmentState == FragmentState.LOADING) ? View.VISIBLE : View.GONE;
int privacyVisibility =
(fragmentState == FragmentState.HAS_POLICY) ? View.VISIBLE : View.GONE;
int lowerSpinnerVisibility =
(fragmentState == FragmentState.WAITING_UNTIL_NEXT_PAGE) ? View.VISIBLE : View.GONE;
CriteriaHelper.pollUiThread(
()
-> Criteria.checkThat(
"Visibility of Loading spinner never reached test setting.",
mCenterSpinner.getVisibility(), Matchers.is(spinnerVisibility)));
Assert.assertEquals("Visibility of ToS text is different than the test setting.",
tosVisibility, mTosText.getVisibility());
Assert.assertEquals("Visibility of Uma Check Box is different than the test setting.",
tosVisibility, mUmaCheckBox.getVisibility());
Assert.assertEquals("Visibility of accept button is different than the test setting.",
tosVisibility, mAcceptButton.getVisibility());
Assert.assertEquals("Visibility of lower spinner is different than the test setting.",
lowerSpinnerVisibility, mLowerSpinner.getVisibility());
Assert.assertEquals("Visibility of privacy disclaimer is different than the test setting.",
privacyVisibility, mPrivacyDisclaimer.getVisibility());
Assert.assertTrue("Uma Check Box should be checked.", mUmaCheckBox.isChecked());
int expectedExitCount = fragmentState == FragmentState.HAS_POLICY ? 1 : 0;
CriteriaHelper.pollUiThread(
() -> Criteria.checkThat(mExitCount, Matchers.is(expectedExitCount)));
}
private void startNativeInitializationAndWait() throws TimeoutException {
Mockito.verify(mInitializer, Mockito.timeout(3000L))
.handlePostNativeStartup(eq(true), mBrowserParts.capture());
Mockito.doCallRealMethod()
.when(mInitializer)
.handlePostNativeStartup(anyBoolean(), any(BrowserParts.class));
TestThreadUtils.runOnUiThreadBlocking(
()
-> mInitializer.handlePostNativeStartup(
/*isAsync*/ false, mBrowserParts.getValue()));
mOnNativeInitializedHelper.waitForCallback("native never initialized.", 0);
}
/**
* Asserts the speed histograms related to FirstRunAppRestrictions and TosAndUmaFirstRunFragment
* are recorded correctly. Noting that with the current test setup, it is possible that the
* FragmentInflationSpeedCheck might be flaky.
*
* TODO(https://crbug.com/1120859): Move to a different setup once this test file moves to
* robolectric.
*
* @param didLoading If Welcome screen ever attempts to wait and load for policies.
* @param appRestrictionMetricsState {@link SpeedComparedToInflation} for checks regarding
* {@link FirstRunAppRestrictionInfo#getHasAppRestriction(Callback)}
* @param deviceOwnershipMetricsState {@link SpeedComparedToInflation} for checks regarding
* {@link EnterpriseInfo#getDeviceEnterpriseInfo(Callback)}}
* @param policyCheckMetricsState {@link SpeedComparedToInflation} for checks regarding {@link
* PolicyService#isInitializationComplete()}
*/
private void assertHistograms(boolean didLoading,
@SpeedComparedToInflation int appRestrictionMetricsState,
@SpeedComparedToInflation int deviceOwnershipMetricsState,
@SpeedComparedToInflation int policyCheckMetricsState) {
assertSingleHistogram("MobileFre.CctTos.LoadingDuration", didLoading);
// WARNING: These two checks might be flaky with current test setup.
assertSingleHistogram("MobileFre.FragmentInflationSpeed.FasterThanAppRestriction",
appRestrictionMetricsState == SpeedComparedToInflation.SLOWER);
assertSingleHistogram("MobileFre.FragmentInflationSpeed.SlowerThanAppRestriction",
appRestrictionMetricsState == SpeedComparedToInflation.FASTER);
assertSingleHistogram("MobileFre.CctTos.IsDeviceOwnedCheckSpeed2.FasterThanInflation",
deviceOwnershipMetricsState == SpeedComparedToInflation.FASTER);
assertSingleHistogram("MobileFre.CctTos.IsDeviceOwnedCheckSpeed2.SlowerThanInflation",
deviceOwnershipMetricsState == SpeedComparedToInflation.SLOWER);
assertSingleHistogram("MobileFre.CctTos.EnterprisePolicyCheckSpeed2.FasterThanInflation",
policyCheckMetricsState == SpeedComparedToInflation.FASTER);
assertSingleHistogram("MobileFre.CctTos.EnterprisePolicyCheckSpeed2.SlowerThanInflation",
policyCheckMetricsState == SpeedComparedToInflation.SLOWER);
}
/**
* Assert MobileFre.PolicyServiceInitDelayAfterNative.* is recorded correctly. The histogram
* should be recorded when {@link PolicyLoadListener} is ready after native initialization.
* @param recorded Whether the histogram should be recorded.
* @param isPolicyFound Used to determine which suffix would have been used.
*/
private void assertPolicyServiceInitDelayAfterNative(boolean recorded, boolean isPolicyFound) {
assertSingleHistogram("MobileFre.PolicyServiceInitDelayAfterNative.WithPolicy2",
recorded && isPolicyFound);
assertSingleHistogram("MobileFre.PolicyServiceInitDelayAfterNative.WithoutPolicy2",
recorded && !isPolicyFound);
}
private void assertSingleHistogram(String histogram, boolean recorded) {
Assert.assertEquals("Histogram <" + histogram + "> is not recorded correctly.",
recorded ? 1 : 0, RecordHistogram.getHistogramTotalCountForTesting(histogram));
}
private void setAppRestrictionsMockNotInitialized() {
Mockito.doAnswer(invocation -> {
Callback<Boolean> callback = invocation.getArgument(0);
mAppRestrictionsCallbacks.add(callback);
return null;
})
.when(mMockAppRestrictionInfo)
.getHasAppRestriction(any());
Mockito.doAnswer(invocation -> {
Callback<Long> callback = invocation.getArgument(0);
mAppRestrictionsDurationCallbacks.add(callback);
return null;
})
.when(mMockAppRestrictionInfo)
.getCompletionElapsedRealtimeMs(any());
}
private void setAppRestrictionsMockInitialized(boolean hasAppRestrictions) {
Mockito.doAnswer(invocation -> {
Callback<Boolean> callback = invocation.getArgument(0);
callback.onResult(hasAppRestrictions);
return null;
})
.when(mMockAppRestrictionInfo)
.getHasAppRestriction(any());
long resolvingTime = SystemClock.elapsedRealtime();
Mockito.doAnswer(invocation -> {
Callback<Long> callback = invocation.getArgument(0);
callback.onResult(resolvingTime);
return null;
})
.when(mMockAppRestrictionInfo)
.getCompletionElapsedRealtimeMs(any());
TestThreadUtils.runOnUiThreadBlocking(() -> {
for (Callback<Boolean> callback : mAppRestrictionsCallbacks) {
callback.onResult(hasAppRestrictions);
}
for (Callback<Long> callback : mAppRestrictionsDurationCallbacks) {
callback.onResult(resolvingTime);
}
});
}
private void setPolicyServiceMockNotInitialized() {
Mockito.when(mPolicyService.isInitializationComplete()).thenReturn(false);
Mockito.doAnswer(invocation -> {
PolicyService.Observer observer = invocation.getArgument(0);
mPolicyServiceObservers.add(observer);
return null;
})
.when(mPolicyService)
.addObserver(any());
}
private void setPolicyServiceMockInitializedWithDialogEnabled(boolean cctTosDialogEnabled) {
setMockCctTosDialogEnabled(cctTosDialogEnabled);
Mockito.when(mPolicyService.isInitializationComplete()).thenReturn(true);
TestThreadUtils.runOnUiThreadBlocking(() -> {
for (PolicyService.Observer observer : mPolicyServiceObservers) {
observer.onPolicyServiceInitialized();
}
});
mPolicyServiceObservers.clear();
}
private void setMockCctTosDialogEnabled(boolean cctTosDialogEnabled) {
Mockito.when(mFirstRunUtils.getCctTosDialogEnabled()).thenReturn(cctTosDialogEnabled);
}
private void setEnterpriseInfoNotInitialized() {
Mockito.doAnswer(invocation -> {
Callback<EnterpriseInfo.OwnedState> callback = invocation.getArgument(0);
mOwnedStateCallbacks.add(callback);
return null;
})
.when(mMockEnterpriseInfo)
.getDeviceEnterpriseInfo(any());
}
private void setEnterpriseInfoInitializedWithDeviceOwner(boolean hasDeviceOwner) {
setEnterpriseInfoInitializedWithOwnedState(
new EnterpriseInfo.OwnedState(hasDeviceOwner, false));
}
private void setEnterpriseInfoInitializedWithOwnedState(EnterpriseInfo.OwnedState ownedState) {
Mockito.doAnswer(invocation -> {
Callback<EnterpriseInfo.OwnedState> callback = invocation.getArgument(0);
callback.onResult(ownedState);
return null;
})
.when(mMockEnterpriseInfo)
.getDeviceEnterpriseInfo(any());
TestThreadUtils.runOnUiThreadBlocking(() -> {
for (Callback<EnterpriseInfo.OwnedState> callback : mOwnedStateCallbacks) {
callback.onResult(ownedState);
}
});
}
private void setMetricsReportDisabled() {
SharedPreferencesManager.getInstance().writeBoolean(
ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, false);
Assert.assertFalse("Crash report should be disabled by shared preference.",
PrivacyPreferencesManagerImpl.getInstance()
.isUsageAndCrashReportingPermittedByUser());
}
private void renderWithPortraitAndLandscape(View tosAndUmaFragmentView, String testPrefix)
throws Exception {
mRenderTestRule.render(tosAndUmaFragmentView, testPrefix + "_portrait");
setDeviceOrientation(tosAndUmaFragmentView, Configuration.ORIENTATION_LANDSCAPE);
mRenderTestRule.render(tosAndUmaFragmentView, testPrefix + "_landscape");
setDeviceOrientation(tosAndUmaFragmentView, Configuration.ORIENTATION_PORTRAIT);
mRenderTestRule.render(tosAndUmaFragmentView, testPrefix + "_portrait");
}
private void setDeviceOrientation(View tosAndUmaFragmentView, int orientation) {
// TODO(https://crbug.com/1133789): This function is copied mostly copied from
// TabUiTestHelper#rotateDeviceToOrientation. Merge / move these two test functions if
// applicable.
if (mActivity.getResources().getConfiguration().orientation == orientation) return;
assertTrue(orientation == Configuration.ORIENTATION_LANDSCAPE
|| orientation == Configuration.ORIENTATION_PORTRAIT);
boolean isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE;
mActivity.setRequestedOrientation(isLandscape ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
: ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
CriteriaHelper.pollUiThread(() -> {
Criteria.checkThat(
mActivity.getResources().getConfiguration().orientation, is(orientation));
Criteria.checkThat(tosAndUmaFragmentView.getWidth() > tosAndUmaFragmentView.getHeight(),
is(isLandscape));
});
}
}