Commit f200a2d8 authored by Sky Malice's avatar Sky Malice Committed by Commit Bot

Only skip ToS for fully managed devices.

Bug: 1108553
Change-Id: Ifa4f7d45a45ebcc8209cf0b1a83da25089a8fd5b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2363881
Commit-Queue: Sky Malice <skym@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799805}
parent 099807e9
......@@ -8,11 +8,11 @@ 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;
import org.chromium.chrome.browser.policy.EnterpriseInfo;
import org.chromium.chrome.browser.policy.PolicyServiceFactory;
import org.chromium.components.browser_ui.widget.LoadingView;
import org.chromium.policy.PolicyService;
......@@ -56,12 +56,20 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
* 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;
/**
* Whether the current device is organization owned. This will start null before the check
* occurs. The FRE can only be skipped if the device is owned corporate owned.
*/
private @Nullable Boolean mIsDeviceOwned;
private TosAndUmaFirstRunFragmentWithEnterpriseSupport() {
mCallbackController = new CallbackController();
checkAppRestriction();
// It's possible for app restrictions to have its callback synchronously invoked and we can
// give up on the skip scenario.
if (shouldWaitForPolicyLoading()) {
checkIsDeviceOwned();
}
}
@Override
......@@ -114,7 +122,7 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
@Override
public void onHideLoadingUIComplete() {
if (confirmedCctTosDialogDisabled()) {
if (confirmedCctTosDialogDisabled() && confirmedOwnedDevice()) {
// TODO(crbug.com/1108564): Show the different UI that has the enterprise disclosure.
exitCctFirstRun();
} else {
......@@ -130,7 +138,14 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
* and can update the UI immediately.
*/
private boolean shouldWaitForPolicyLoading() {
return !confirmedNoAppRestriction() && mPolicyCctTosDialogEnabled == null;
// Note that someSignalOutstanding doesn't care about mHasRestriction. It's main purpose is
// to be a very quick signal mPolicyCctTosDialogEnabled is never going to turn false. But
// once mPolicyCctTosDialogEnabled has a non-null value, mHasRestriction is redundant. It
// never actually needs to return for us to know we can skip the ToS.
boolean someSignalOutstanding =
mPolicyCctTosDialogEnabled == null || mIsDeviceOwned == null;
boolean mightStillBeAllowedToSkip = !confirmedToShowUmaAndTos();
return someSignalOutstanding && mightStillBeAllowedToSkip;
}
/**
......@@ -140,7 +155,8 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
* @return Whether we should show TosAndUma components on the UI.
*/
private boolean confirmedToShowUmaAndTos() {
return confirmedNoAppRestriction() || confirmedCctTosDialogEnabled();
return confirmedNoAppRestriction() || confirmedCctTosDialogEnabled()
|| confirmedNotOwnedDevice();
}
private boolean confirmedNoAppRestriction() {
......@@ -155,16 +171,32 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
return mPolicyCctTosDialogEnabled != null && !mPolicyCctTosDialogEnabled;
}
private boolean confirmedNotOwnedDevice() {
return mIsDeviceOwned != null && !mIsDeviceOwned;
}
private boolean confirmedOwnedDevice() {
return mIsDeviceOwned != null && mIsDeviceOwned;
}
private void checkAppRestriction() {
FirstRunAppRestrictionInfo.getInstance().getHasAppRestriction(
mCallbackController.makeCancelable(this::onAppRestrictionDetected));
}
private void onAppRestrictionDetected(boolean hasAppRestriction) {
// It's possible that we've already told the spinner to hide, and even signaled to our
// delegate to exit. If so, we can ignore the app restrictions value.
// TODO(https://crbug.com/1119449): Shouldn't need this check if we can cancel this callback
// when we no longer need it.
if (!shouldWaitForPolicyLoading()) {
return;
}
mHasRestriction = hasAppRestriction;
if (!shouldWaitForPolicyLoading() && mViewCreated) {
// TODO(crbug.com/1106812): Unregister policy listener.
// TODO(https://crbug.com/1119449): Cleanup various policy callbacks.
mLoadingSpinner.hideLoadingUI();
}
}
......@@ -185,14 +217,28 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
private void updateCctTosPolicy() {
mPolicyCctTosDialogEnabled = FirstRunUtils.isCctTosDialogEnabled();
if (mViewCreated) {
if (!shouldWaitForPolicyLoading() && mViewCreated) {
// TODO(https://crbug.com/1119449): Cleanup various policy callbacks.
mLoadingSpinner.hideLoadingUI();
}
}
private void checkIsDeviceOwned() {
EnterpriseInfo.getInstance().getDeviceEnterpriseInfo(
mCallbackController.makeCancelable(this::onIsDeviceOwnedDetected));
}
private void onIsDeviceOwnedDetected(EnterpriseInfo.OwnedState ownedState) {
mIsDeviceOwned = ownedState.mDeviceOwned;
if (!shouldWaitForPolicyLoading() && mViewCreated) {
// TODO(https://crbug.com/1119449): Cleanup various policy callbacks.
mLoadingSpinner.hideLoadingUI();
}
}
@VisibleForTesting
void exitCctFirstRun() {
private void exitCctFirstRun() {
assert confirmedCctTosDialogDisabled();
assert confirmedOwnedDevice();
// 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.
......
......@@ -29,7 +29,7 @@ import java.util.concurrent.RejectedExecutionException;
/**
* Provide the enterprise information for the current device and profile.
*/
public final class EnterpriseInfo {
public class EnterpriseInfo {
private static final String TAG = "EnterpriseInfo";
private static EnterpriseInfo sInstance;
......@@ -40,9 +40,10 @@ public final class EnterpriseInfo {
private boolean mSkipAsyncCheckForTesting;
static class OwnedState {
final boolean mDeviceOwned;
final boolean mProfileOwned;
/** A simple tuple to hold onto named fields about the state of ownership. */
public static class OwnedState {
public final boolean mDeviceOwned;
public final boolean mProfileOwned;
public OwnedState(boolean isDeviceOwned, boolean isProfileOwned) {
mDeviceOwned = isDeviceOwned;
......@@ -70,6 +71,11 @@ public final class EnterpriseInfo {
return sInstance;
}
@VisibleForTesting
public static void setInstanceForTest(EnterpriseInfo instance) {
sInstance = instance;
}
/**
* Returns, via callback, whether the device has a device owner or a profile owner.
*/
......
......@@ -41,6 +41,7 @@ import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.locale.DefaultSearchEngineDialogHelperUtils;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.locale.LocaleManager.SearchEnginePromoType;
import org.chromium.chrome.browser.policy.EnterpriseInfo;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.MultiActivityTestRule;
......@@ -66,6 +67,8 @@ public class FirstRunIntegrationTest {
@Mock
public FirstRunAppRestrictionInfo mMockAppRestrictionInfo;
@Mock
public EnterpriseInfo mEntepriseInfo;
private final Set<Class> mSupportedActivities =
CollectionUtil.newHashSet(ChromeLauncherActivity.class, FirstRunActivity.class,
......@@ -95,6 +98,7 @@ public class FirstRunIntegrationTest {
public void tearDown() {
FirstRunActivity.setEnableEnterpriseCCTForTest(false);
FirstRunAppRestrictionInfo.setInstanceForTest(null);
EnterpriseInfo.setInstanceForTest(null);
if (mLastActivity != null) mLastActivity.finish();
}
......@@ -123,6 +127,17 @@ public class FirstRunIntegrationTest {
FirstRunAppRestrictionInfo.setInstanceForTest(mMockAppRestrictionInfo);
}
private void setDeviceOwnedForMock() {
Mockito.doAnswer(invocation -> {
Callback<EnterpriseInfo.OwnedState> callback = invocation.getArgument(0);
callback.onResult(new EnterpriseInfo.OwnedState(true, false));
return null;
})
.when(mEntepriseInfo)
.getDeviceEnterpriseInfo(any());
EnterpriseInfo.setInstanceForTest(mEntepriseInfo);
}
@Test
@SmallTest
public void testHelpPageSkipsFirstRun() {
......@@ -259,6 +274,7 @@ public class FirstRunIntegrationTest {
Bundle restrictions = new Bundle();
restrictions.putBoolean("CCTToSDialogEnabled", false);
AbstractAppRestrictionsProvider.setTestRestrictions(restrictions);
setDeviceOwnedForMock();
Intent intent =
CustomTabsTestUtils.createMinimalCustomTabIntent(mContext, "https://test.com");
......
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