Commit 6246c58f authored by Wenyu Fu's avatar Wenyu Fu Committed by Commit Bot

[CCTToSFRE] Skip FRE in CCT for Enterprise workflow

The main workflow on how we change FRE when launching through CCT for
Enterprise clients. This CL also adds some generic integration tests for
basic test coverage. Once policy is ready, we'll fulfill test cases with
more detail.

Bug: 1106987
Change-Id: I24530156f465ca7b8729e7dee5bdfb211a0ea664
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2320768
Commit-Queue: Wenyu Fu <wenyufu@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarSky Malice <skym@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795241}
parent 3de93463
...@@ -740,6 +740,7 @@ chrome_java_sources = [ ...@@ -740,6 +740,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/firstrun/SigninFirstRunFragment.java", "java/src/org/chromium/chrome/browser/firstrun/SigninFirstRunFragment.java",
"java/src/org/chromium/chrome/browser/firstrun/TabbedModeFirstRunActivity.java", "java/src/org/chromium/chrome/browser/firstrun/TabbedModeFirstRunActivity.java",
"java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java", "java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java",
"java/src/org/chromium/chrome/browser/firstrun/TosAndUmaCctFirstRunFragment.java",
"java/src/org/chromium/chrome/browser/flags/ChromeSessionState.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/BrowserControlsManager.java",
"java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java", "java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java",
......
...@@ -198,6 +198,7 @@ chrome_test_java_sources = [ ...@@ -198,6 +198,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivityTestObserver.java", "javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivityTestObserver.java",
"javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java",
"javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java", "javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java",
"javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaCctFirstRunFragmentTest.java",
"javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java", "javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java",
"javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTestUtils.java", "javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTestUtils.java",
"javatests/src/org/chromium/chrome/browser/gcore/MockConnectedTask.java", "javatests/src/org/chromium/chrome/browser/gcore/MockConnectedTask.java",
......
...@@ -45,6 +45,15 @@ ...@@ -45,6 +45,15 @@
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
android:src="@drawable/fre_product_logo" /> android:src="@drawable/fre_product_logo" />
<ProgressBar
android:id="@+id/progress_spinner_large"
style="@style/Widget.AppCompat.ProgressBar"
android:layout_marginTop="@dimen/fre_vertical_spacing"
android:layout_gravity="bottom|center_horizontal"
android:layout_width="48dp"
android:layout_height="48dp"
android:visibility="gone"/>
<LinearLayout <LinearLayout
android:id="@+id/fre_content_wrapper" android:id="@+id/fre_content_wrapper"
android:layout_width="0dp" android:layout_width="0dp"
......
...@@ -78,6 +78,8 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa ...@@ -78,6 +78,8 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa
private static final int FRE_PROGRESS_MAX = 7; private static final int FRE_PROGRESS_MAX = 7;
private static FirstRunActivityObserver sObserver; private static FirstRunActivityObserver sObserver;
// TODO(wenyufu): Remove when MVP for crbug.com/1103476 is complete.
private static boolean sEnableEnterpriseCCT;
private String mResultSignInAccountName; private String mResultSignInAccountName;
private boolean mResultIsDefaultAccount; private boolean mResultIsDefaultAccount;
...@@ -100,6 +102,7 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa ...@@ -100,6 +102,7 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa
* Android app list. * Android app list.
*/ */
private boolean mLaunchedFromChromeIcon; private boolean mLaunchedFromChromeIcon;
private boolean mLaunchedFromCCT;
private final List<FirstRunPage> mPages = new ArrayList<>(); private final List<FirstRunPage> mPages = new ArrayList<>();
private final List<Integer> mFreProgressStates = new ArrayList<>(); private final List<Integer> mFreProgressStates = new ArrayList<>();
...@@ -113,7 +116,9 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa ...@@ -113,7 +116,9 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa
* Defines a sequence of pages to be shown (depending on parameters etc). * Defines a sequence of pages to be shown (depending on parameters etc).
*/ */
private void createPageSequence() { private void createPageSequence() {
mPages.add(new ToSAndUMAFirstRunFragment.Page()); mPages.add(sEnableEnterpriseCCT && mLaunchedFromCCT
? new TosAndUmaCctFirstRunFragment.Page()
: new ToSAndUMAFirstRunFragment.Page());
mFreProgressStates.add(FRE_PROGRESS_WELCOME_SHOWN); mFreProgressStates.add(FRE_PROGRESS_WELCOME_SHOWN);
// Other pages will be created by createPostNativePageSequence() after // Other pages will be created by createPostNativePageSequence() after
// native has been initialized. // native has been initialized.
...@@ -381,6 +386,11 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa ...@@ -381,6 +386,11 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa
SearchWidgetProvider.updateCachedEngineName(); SearchWidgetProvider.updateCachedEngineName();
if (sObserver != null) sObserver.onUpdateCachedEngineName(); if (sObserver != null) sObserver.onUpdateCachedEngineName();
exitFirstRun();
}
@Override
public void exitFirstRun() {
if (!sendFirstRunCompletePendingIntent()) { if (!sendFirstRunCompletePendingIntent()) {
finish(); finish();
} else { } else {
...@@ -440,6 +450,8 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa ...@@ -440,6 +450,8 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa
if (getIntent() != null) { if (getIntent() != null) {
mLaunchedFromChromeIcon = mLaunchedFromChromeIcon =
getIntent().getBooleanExtra(EXTRA_COMING_FROM_CHROME_ICON, false); getIntent().getBooleanExtra(EXTRA_COMING_FROM_CHROME_ICON, false);
mLaunchedFromCCT =
getIntent().getBooleanExtra(EXTRA_CHROME_LAUNCH_INTENT_IS_CCT, false);
} }
} }
...@@ -504,4 +516,9 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa ...@@ -504,4 +516,9 @@ public class FirstRunActivity extends FirstRunActivityBase implements FirstRunPa
assert sObserver == null; assert sObserver == null;
sObserver = observer; sObserver = observer;
} }
@VisibleForTesting
public static void setEnableEnterpriseCCTForTest(boolean isEnabled) {
sEnableEnterpriseCCT = isEnabled;
}
} }
...@@ -80,18 +80,20 @@ class FirstRunAppRestrictionInfo { ...@@ -80,18 +80,20 @@ class FirstRunAppRestrictionInfo {
*/ */
public static void destroy() { public static void destroy() {
ThreadUtils.assertOnUiThread(); ThreadUtils.assertOnUiThread();
if (sInstance != null) { if (sInstance != null) sInstance.destroyInternal();
if (sInstance.mFetchAppRestrictionAsyncTask != null) {
sInstance.mFetchAppRestrictionAsyncTask.cancel(true);
}
if (sInstance.mProvider != null) {
sInstance.mProvider.destroy();
}
sInstance.mCallBacks.clear();
}
sInstance = null; sInstance = null;
} }
private void destroyInternal() {
if (mFetchAppRestrictionAsyncTask != null) {
mFetchAppRestrictionAsyncTask.cancel(true);
}
if (mProvider != null) {
mProvider.destroy();
}
mCallBacks.clear();
}
/** /**
* Register a callback whether app restriction is found on device. If app restrictions have * Register a callback whether app restriction is found on device. If app restrictions have
* already been fetched, the callback will be invoked immediately. * already been fetched, the callback will be invoked immediately.
...@@ -163,4 +165,9 @@ class FirstRunAppRestrictionInfo { ...@@ -163,4 +165,9 @@ class FirstRunAppRestrictionInfo {
mCallBacks.remove().onResult(mHasAppRestriction); mCallBacks.remove().onResult(mHasAppRestriction);
} }
} }
@VisibleForTesting
public static void setInstanceForTest(FirstRunAppRestrictionInfo testInstance) {
sInstance = testInstance;
}
} }
...@@ -33,6 +33,16 @@ public interface FirstRunPageDelegate { ...@@ -33,6 +33,16 @@ public interface FirstRunPageDelegate {
*/ */
void completeFirstRunExperience(); void completeFirstRunExperience();
/**
* Exit the First Run Experience without marking the flow complete. This will finish the first
* run activity and start the main activity without setting any of the preferences tracking
* whether first run has been completed.
*
* Exposing this function is intended for use in scenarios where FRE is partially or completely
* skipped. (e.g. in accordance with Enterprise polices)
*/
void exitFirstRun();
/** /**
* Notifies that the user refused to sign in (e.g. "NO, THANKS"). * Notifies that the user refused to sign in (e.g. "NO, THANKS").
*/ */
......
...@@ -44,12 +44,13 @@ public class ToSAndUMAFirstRunFragment extends Fragment implements FirstRunFragm ...@@ -44,12 +44,13 @@ public class ToSAndUMAFirstRunFragment extends Fragment implements FirstRunFragm
} }
} }
protected boolean mNativeInitialized;
private Button mAcceptButton; private Button mAcceptButton;
private CheckBox mSendReportCheckBox; private CheckBox mSendReportCheckBox;
private TextView mTosAndPrivacy; private TextView mTosAndPrivacy;
private View mTitle; private View mTitle;
private View mProgressSpinner; private View mProgressSpinner;
private boolean mNativeInitialized;
private boolean mTriggerAcceptAfterNativeInit; private boolean mTriggerAcceptAfterNativeInit;
@Override @Override
...@@ -76,7 +77,7 @@ public class ToSAndUMAFirstRunFragment extends Fragment implements FirstRunFragm ...@@ -76,7 +77,7 @@ public class ToSAndUMAFirstRunFragment extends Fragment implements FirstRunFragm
} }
}); });
if (ChromeVersionInfo.isOfficialBuild()) { if (canShowUmaCheckBox()) {
int paddingStart = getResources().getDimensionPixelSize( int paddingStart = getResources().getDimensionPixelSize(
R.dimen.fre_tos_checkbox_padding); R.dimen.fre_tos_checkbox_padding);
ViewCompat.setPaddingRelative(mSendReportCheckBox, ViewCompat.setPaddingRelative(mSendReportCheckBox,
...@@ -180,11 +181,31 @@ public class ToSAndUMAFirstRunFragment extends Fragment implements FirstRunFragm ...@@ -180,11 +181,31 @@ public class ToSAndUMAFirstRunFragment extends Fragment implements FirstRunFragm
private void setSpinnerVisible(boolean spinnerVisible) { private void setSpinnerVisible(boolean spinnerVisible) {
// When the progress spinner is visible, we hide the other UI elements so that // When the progress spinner is visible, we hide the other UI elements so that
// the user can't interact with them. // the user can't interact with them.
int otherElementsVisible = spinnerVisible ? View.INVISIBLE : View.VISIBLE; boolean otherElementVisible = !spinnerVisible;
mTitle.setVisibility(otherElementsVisible);
mAcceptButton.setVisibility(otherElementsVisible); setTosAndUmaVisible(otherElementVisible);
mTosAndPrivacy.setVisibility(otherElementsVisible); mTitle.setVisibility(otherElementVisible ? View.VISIBLE : View.INVISIBLE);
mSendReportCheckBox.setVisibility(otherElementsVisible);
mProgressSpinner.setVisibility(spinnerVisible ? View.VISIBLE : View.GONE); mProgressSpinner.setVisibility(spinnerVisible ? View.VISIBLE : View.GONE);
} }
// Exposed methods for ToSAndUMACCTFirstRunFragment
protected void setTosAndUmaVisible(boolean isVisible) {
int visibility = isVisible ? View.VISIBLE : View.INVISIBLE;
mAcceptButton.setVisibility(visibility);
mTosAndPrivacy.setVisibility(visibility);
// Avoid updating visibility if the UMA check box can't be shown right now.
if (canShowUmaCheckBox()) {
mSendReportCheckBox.setVisibility(visibility);
}
}
/**
* @return Whether the check box for Uma metrics can be shown. It should be used in conjunction
* with whether other non-spinner elements can generally be shown.
*/
protected boolean canShowUmaCheckBox() {
return ChromeVersionInfo.isOfficialBuild();
}
} }
// 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.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.CallbackController;
import org.chromium.base.Log;
import org.chromium.chrome.R;
/**
* Another FirstRunFragment that is only used when running with CCT.
*/
public class TosAndUmaCctFirstRunFragment extends ToSAndUMAFirstRunFragment {
private static final String TAG = "TosAndUmaCctFre";
/** FRE page that instantiates this fragment. */
public static class Page implements FirstRunPage<TosAndUmaCctFirstRunFragment> {
@Override
public boolean shouldSkipPageOnCreate() {
// TODO(crbug.com/1111490): Revisit during post-MVP.
// There's an edge case where we accept the welcome page in the main app, abort the FRE,
// then go through this CCT FRE again.
return FirstRunStatus.shouldSkipWelcomePage();
}
@Override
public TosAndUmaCctFirstRunFragment instantiateFragment() {
return new TosAndUmaCctFirstRunFragment();
}
}
private boolean mViewCreated;
private View mLargeSpinner;
private CallbackController mCallbackController;
/**
* Whether app restriction is found on the device. This can be null when this information is not
* ready yet.
*/
private @Nullable Boolean mHasRestriction;
/**
* The value of CCTToSDialogEnabled policy on the device. If the value is false, it means we
* should skip the rest of FRE. This can be null when this information is not ready yet.
*/
private @Nullable Boolean mPolicyCctTosDialogEnabled;
private static boolean sBlockPolicyLoadingForTest;
private TosAndUmaCctFirstRunFragment() {
mCallbackController = new CallbackController();
checkAppRestriction();
}
@Override
public void onDestroy() {
if (mCallbackController != null) {
mCallbackController.destroy();
mCallbackController = null;
}
super.onDestroy();
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mLargeSpinner = view.findViewById(R.id.progress_spinner_large);
mViewCreated = true;
if (shouldWaitForPolicyLoading()) {
// TODO(crbug.com/1106987): Post a task to show the LargeSpinner after 500ms and make
// sure it appears 500 ms at least.
mLargeSpinner.setVisibility(View.VISIBLE);
setTosAndUmaVisible(false);
} else {
updateViewOnEnterpriseChecksComplete();
}
}
@Override
public void onNativeInitialized() {
super.onNativeInitialized();
if (shouldWaitForPolicyLoading()) {
checkEnterprisePolicies();
}
}
@Override
protected boolean canShowUmaCheckBox() {
return super.canShowUmaCheckBox() && shouldShowUmaAndTos();
}
/**
* @return True if we need to wait on an Async tasks that determine whether any Enterprise
* policies needs to be applied. If this returns false, then we no longer need to wait
* and can update the UI immediately.
*/
private boolean shouldWaitForPolicyLoading() {
return (mHasRestriction == null || mHasRestriction) && mPolicyCctTosDialogEnabled == null;
}
private boolean shouldShowUmaAndTos() {
return (mHasRestriction != null && !mHasRestriction)
|| (mPolicyCctTosDialogEnabled != null && mPolicyCctTosDialogEnabled);
}
private void checkAppRestriction() {
FirstRunAppRestrictionInfo.getInstance().getHasAppRestriction(
mCallbackController.makeCancelable(this::onAppRestrictionDetected));
}
@VisibleForTesting
void onAppRestrictionDetected(boolean hasAppRestriction) {
mHasRestriction = hasAppRestriction;
if (!shouldWaitForPolicyLoading() && mViewCreated) {
// TODO(crbug.com/1106812): Unregister policy listener.
updateViewOnEnterpriseChecksComplete();
}
}
private void checkEnterprisePolicies() {
// TODO(crbug.com/1106812): Monitor policy changes when it is ready.
if (!sBlockPolicyLoadingForTest) {
onCctTosPolicyDetected(getPolicyCctTosDialogEnabled());
}
}
private boolean getPolicyCctTosDialogEnabled() {
// TODO(crbug.com/1108118): Do the actual fetching for CCT Policy to replace the fake one.
return true;
}
@VisibleForTesting
void onCctTosPolicyDetected(boolean cctTosDialogEnabled) {
mPolicyCctTosDialogEnabled = cctTosDialogEnabled;
updateViewOnEnterpriseChecksComplete();
}
/**
* Update the UI based on aggregated signal whether ToS / UMA should be shown.
*/
private void updateViewOnEnterpriseChecksComplete() {
if (shouldShowUmaAndTos()) {
mLargeSpinner.setVisibility(View.GONE);
setTosAndUmaVisible(true);
return;
}
assert mPolicyCctTosDialogEnabled != null && !mPolicyCctTosDialogEnabled;
// TODO(crbug.com/1108564): Show the different UI that has the enterprise disclosure.
// TODO(crbug.com/1106987): Post a task to show the LargeSpinner after 500ms and make sure
// it appears 500 ms at least.
mLargeSpinner.setVisibility(View.GONE);
exitCctFirstRun();
}
@VisibleForTesting
void exitCctFirstRun() {
// TODO(crbug.com/1108564): Fire a signal to end this fragment when disclaimer is ready.
// TODO(crbug.com/1108582): Save a shared pref indicating Enterprise CCT FRE is complete,
// and skip waiting for future cold starts.
Log.d(TAG, "ToSAndUMACCTFirstRunFragment finished.");
getPageDelegate().exitFirstRun();
}
@VisibleForTesting
static void setBlockPolicyLoadingForTest(boolean blockPolicyLoadingForTest) {
sBlockPolicyLoadingForTest = blockPolicyLoadingForTest;
}
}
// Copyright 2015 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 android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
import android.content.Context;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.view.View;
import androidx.annotation.IntDef;
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.MockitoAnnotations;
import org.chromium.base.Callback;
import org.chromium.base.CommandLine;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
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;
/**
* Test for first run activity and {@link TosAndUmaCctFirstRunFragment}.
* 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 TosAndUmaCctFirstRunFragmentTest {
@IntDef({FragmentState.LOADING, FragmentState.NO_POLICY, FragmentState.HAS_POLICY})
@Retention(RetentionPolicy.SOURCE)
@interface FragmentState {
int LOADING = 0;
int NO_POLICY = 1;
int HAS_POLICY = 2;
}
@Rule
public DisableAnimationsTestRule mDisableAnimationsTestRule = new DisableAnimationsTestRule();
@Mock
public FirstRunAppRestrictionInfo mMockAppRestrictionInfo;
private FirstRunActivityTestObserver mTestObserver = new FirstRunActivityTestObserver();
private FirstRunActivity mActivity;
private TosAndUmaCctFirstRunFragment mFragment;
private View mTosText;
private View mAcceptButton;
private View mLargeSpinner;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Assert.assertFalse(
CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE));
// Static switches.
FirstRunActivity.setEnableEnterpriseCCTForTest(true);
FirstRunAppRestrictionInfo.setInstanceForTest(mMockAppRestrictionInfo);
TosAndUmaCctFirstRunFragment.setBlockPolicyLoadingForTest(true);
}
@After
public void tearDown() {
FirstRunActivity.setEnableEnterpriseCCTForTest(false);
FirstRunAppRestrictionInfo.setInstanceForTest(null);
TosAndUmaCctFirstRunFragment.setBlockPolicyLoadingForTest(false);
if (mActivity != null) mActivity.finish();
}
@Test
@SmallTest
public void testNoRestriction() {
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
TestThreadUtils.runOnUiThreadBlocking(() -> mFragment.onAppRestrictionDetected(false));
assertUIState(FragmentState.NO_POLICY);
}
@Test
@SmallTest
public void testWithRestriction_NoPolicy() {
setHasAppRestrictionForMock();
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
waitUntilNativeLoaded();
// TODO(crbug.com/1108118): In our current test setup, #onCctPolicyDetected will actually
// called inside #onNativeInitialized. When we decouple these two signals, we should update
// the test accordingly.
TestThreadUtils.runOnUiThreadBlocking(() -> mFragment.onCctTosPolicyDetected(true));
assertUIState(FragmentState.NO_POLICY);
}
@Test
@SmallTest
public void testWithRestriction_WithPolicy() {
setHasAppRestrictionForMock();
launchFirstRunThroughCustomTab();
assertUIState(FragmentState.LOADING);
waitUntilNativeLoaded();
TestThreadUtils.runOnUiThreadBlocking(() -> mFragment.onCctTosPolicyDetected(false));
assertUIState(FragmentState.HAS_POLICY);
Mockito.verify(mFragment).exitCctFirstRun();
}
/**
* Launch chrome through custom tab and trigger first run.
*/
private void launchFirstRunThroughCustomTab() {
FirstRunActivity.setObserverForTest(mTestObserver);
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);
mFragment = Mockito.spy((TosAndUmaCctFirstRunFragment) mActivity.getSupportFragmentManager()
.getFragments()
.get(0));
mTosText = mActivity.findViewById(R.id.tos_and_privacy);
mAcceptButton = mActivity.findViewById(R.id.tos_and_privacy);
mLargeSpinner = mActivity.findViewById(R.id.progress_spinner_large);
}
private void assertUIState(@FragmentState int fragmentState) {
int tosVisibility = View.INVISIBLE;
int spinnerVisibility = View.GONE;
if (fragmentState == FragmentState.NO_POLICY) {
tosVisibility = View.VISIBLE;
}
if (fragmentState == FragmentState.LOADING) {
spinnerVisibility = View.VISIBLE;
}
Assert.assertEquals("Visibility of ToS text is different than the test setting.",
tosVisibility, mTosText.getVisibility());
Assert.assertEquals("Visibility of accept button is different than the test setting.",
tosVisibility, mAcceptButton.getVisibility());
Assert.assertEquals("Visibility of Loading spinner is different than the test setting.",
spinnerVisibility, mLargeSpinner.getVisibility());
}
/** Set up mock FirstRunAppRestrictionInfo that there is app restriction on the device */
private void setHasAppRestrictionForMock() {
Mockito.doAnswer(invocation -> {
Callback<Boolean> callback = invocation.getArgument(0);
callback.onResult(true);
return null;
})
.when(mMockAppRestrictionInfo)
.getHasAppRestriction(any());
}
private void waitUntilNativeLoaded() {
CriteriaHelper.pollUiThread(
(() -> mActivity.isNativeSideIsInitializedForTest()), "native never initialized.");
}
}
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