Commit 453b6ffe authored by Wenyu Fu's avatar Wenyu Fu Committed by Commit Bot

[CCTToSFRE] Add privacy disclaimer when ToS is skipped

Add a privacy disclosure when ToS is skipped by policy in the FRE. The
privacy disclaimer will be displayed on screen for 1 second before FRE
is finished.

Bug: 1108564, 1128158
Change-Id: I5f912e62484a5255bfda27db0318c0e92d541903
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2548293
Commit-Queue: Wenyu Fu <wenyufu@chromium.org>
Reviewed-by: default avatarSky Malice <skym@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#830685}
parent 3e345e0a
......@@ -851,6 +851,7 @@ chrome_java_resources = [
"java/res/layout/find_in_page.xml",
"java/res/layout/find_toolbar.xml",
"java/res/layout/fre_data_reduction_proxy_lite_mode.xml",
"java/res/layout/fre_tos_privacy_disclaimer.xml",
"java/res/layout/fre_tosanduma.xml",
"java/res/layout/history_clear_browsing_data_header.xml",
"java/res/layout/history_item_view.xml",
......
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/privacy_disclaimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/fre_policy_privacy_disclaimer_icon_padding"
android:drawableStart="@drawable/ic_business"
android:text="@string/fre_browser_managed_by_organization"
android:textAppearance="@style/TextAppearance.TextSmall.Secondary"
app:chromeDrawableTint="@color/default_text_color_secondary"
app:drawableWidth="@dimen/fre_policy_privacy_disclaimer_icon_size"
app:drawableHeight="@dimen/fre_policy_privacy_disclaimer_icon_size"
tools:showIn="@layout/lightweight_fre_tos" />
\ No newline at end of file
......@@ -93,6 +93,14 @@
android:text="@string/fre_send_report_check"
android:paddingStart="@dimen/fre_tos_checkbox_padding"
android:textAppearance="@style/TextAppearance.TextMedium.Primary" />
<include
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/fre_content_margin"
android:layout_marginBottom="@dimen/fre_vertical_spacing"
android:visibility="gone"
layout="@layout/fre_tos_privacy_disclaimer" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
......@@ -137,15 +145,6 @@
android:layout_height="@dimen/fre_bottom_loading_spinner_size"/>
</FrameLayout>
<!-- Place holder for privacy disclosure. -->
<TextView
android:id="@+id/privacy_disclaimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:text="@string/fre_browser_managed_by_organization"
android:visibility="gone"/>
<!-- Empty TextView to preload fonts for following pages. See https://crbug.com/1119990#c20 -->
<TextView
android:layout_width="wrap_content"
......
......@@ -58,6 +58,14 @@
android:layout_width="@dimen/fre_loading_spinner_size"
android:visibility="gone"/>
</FrameLayout>
<include
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:visibility="gone"
layout="@layout/fre_tos_privacy_disclaimer" />
</FrameLayout>
<org.chromium.components.browser_ui.widget.DualControlLayout
......
......@@ -157,6 +157,8 @@
<dimen name="fre_loading_spinner_size">48dp</dimen>
<dimen name="fre_button_padding">12dp</dimen>
<dimen name="fre_bottom_loading_spinner_size">24dp</dimen>
<dimen name="fre_policy_privacy_disclaimer_icon_size">18dp</dimen>
<dimen name="fre_policy_privacy_disclaimer_icon_padding">8dp</dimen>
<dimen name="fre_button_vertical_margin">24dp</dimen>
<dimen name="fre_button_bar_height">62dp</dimen>
......
......@@ -22,6 +22,7 @@ import org.chromium.components.signin.AccountManagerFacadeProvider;
/** Provides first run related utility functions. */
public class FirstRunUtils {
private static Boolean sHasGoogleAccountAuthenticator;
static final int SKIP_TOS_EXIT_DELAY_MS = 1000;
/**
* Synchronizes first run native and Java preferences.
......
......@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.firstrun;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
......@@ -19,6 +20,7 @@ import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.IntentUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.supplier.OneshotSupplierImpl;
import org.chromium.chrome.R;
......@@ -52,12 +54,16 @@ public class LightweightFirstRunActivity
private LoadingView mLoadingView;
private View mLoadingViewContainer;
private View mLightweightFreButtons;
private View mPrivacyDisclaimer;
private boolean mViewCreated;
private boolean mNativeInitialized;
private boolean mTriggerAcceptAfterNativeInit;
private long mViewCreatedTimeMs;
private Handler mHandler;
private Runnable mExitFreRunnable;
public static final String EXTRA_ASSOCIATED_APP_NAME =
"org.chromium.chrome.browser.firstrun.AssociatedAppName";
......@@ -147,6 +153,8 @@ public class LightweightFirstRunActivity
mLoadingView = findViewById(R.id.loading_view);
mLoadingViewContainer = findViewById(R.id.loading_view_container);
mPrivacyDisclaimer = findViewById(R.id.privacy_disclaimer);
mViewCreated = true;
mViewCreatedTimeMs = SystemClock.elapsedRealtime();
......@@ -227,6 +235,10 @@ public class LightweightFirstRunActivity
// As first run is complete, we no longer need FirstRunAppRestrictionInfo.
if (mFirstRunAppRestrictionInfo != null) mFirstRunAppRestrictionInfo.destroy();
if (mSkipTosDialogPolicyListener != null) mSkipTosDialogPolicyListener.destroy();
if (mHandler != null && mExitFreRunnable != null) {
mHandler.removeCallbacks(mExitFreRunnable);
}
}
private void abortFirstRunExperience() {
......@@ -240,9 +252,17 @@ public class LightweightFirstRunActivity
}
private void skipTosByPolicy() {
// TODO(crbug.com/1108564): Show the different UI that has the enterprise disclosure.
FirstRunStatus.setEphemeralSkipFirstRun(true);
exitLightweightFirstRun();
mLoadingViewContainer.setVisibility(View.GONE);
mPrivacyDisclaimer.setVisibility(View.VISIBLE);
mPrivacyDisclaimer.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
mExitFreRunnable = () -> {
FirstRunStatus.setEphemeralSkipFirstRun(true);
exitLightweightFirstRun();
mExitFreRunnable = null;
};
mHandler = new Handler(ThreadUtils.getUiThreadLooper());
mHandler.postDelayed(mExitFreRunnable, FirstRunUtils.SKIP_TOS_EXIT_DELAY_MS);
}
private void exitLightweightFirstRun() {
......
......@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.firstrun;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
......@@ -13,6 +14,7 @@ import android.view.accessibility.AccessibilityEvent;
import androidx.annotation.NonNull;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.supplier.OneshotSupplierImpl;
import org.chromium.chrome.R;
......@@ -64,10 +66,14 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
private boolean mViewCreated;
private View mLoadingSpinnerContainer;
private LoadingView mLoadingSpinner;
private View mPrivacyDisclaimer;
private SkipTosDialogPolicyListener mSkipTosDialogPolicyListener;
private final OneshotSupplierImpl<PolicyService> mPolicyServiceProvider =
new OneshotSupplierImpl<>();
private Handler mHandler;
private Runnable mExitFreRunnable;
/** The {@link SystemClock} timestamp when onViewCreated is called. */
private long mViewCreatedTimeMs;
......@@ -81,6 +87,10 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
mSkipTosDialogPolicyListener.destroy();
mSkipTosDialogPolicyListener = null;
}
if (mHandler != null && mExitFreRunnable != null) {
mHandler.removeCallbacks(mExitFreRunnable);
mHandler = null;
}
super.onDestroy();
}
......@@ -101,6 +111,7 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
mLoadingSpinnerContainer = view.findViewById(R.id.loading_view_container);
mLoadingSpinner = view.findViewById(R.id.progress_spinner_large);
mPrivacyDisclaimer = view.findViewById(R.id.privacy_disclaimer);
mViewCreated = true;
mViewCreatedTimeMs = SystemClock.elapsedRealtime();
......@@ -142,7 +153,6 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
SystemClock.elapsedRealtime() - mViewCreatedTimeMs);
if (mSkipTosDialogPolicyListener.get()) {
// TODO(crbug.com/1108564): Show the different UI that has the enterprise disclosure.
exitCctFirstRun();
} else {
// Else, show the UMA as the loading spinner is GONE.
......@@ -161,10 +171,18 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupport
}
private 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, "TosAndUmaFirstRunFragmentWithEnterpriseSupport finished.");
getPageDelegate().exitFirstRun();
mPrivacyDisclaimer.setVisibility(View.VISIBLE);
mPrivacyDisclaimer.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
mExitFreRunnable = () -> {
getPageDelegate().exitFirstRun();
mExitFreRunnable = null;
};
mHandler = new Handler(ThreadUtils.getUiThreadLooper());
mHandler.postDelayed(mExitFreRunnable, FirstRunUtils.SKIP_TOS_EXIT_DELAY_MS);
}
}
......@@ -17,6 +17,8 @@ import org.chromium.chrome.R;
/**
* Base view for fre_tosanduma.xml. This view may change child view placement when changing screen
* dimensions (e.g. on rotation).
*
* See https://crbug.com/1151537 for illustration.
*/
public class TosAndUmaFragmentView extends FrameLayout {
private ScrollView mScrollView;
......
......@@ -113,6 +113,7 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupportTest {
private View mTosText;
private View mAcceptButton;
private View mLargeSpinner;
private View mPrivacyDisclaimer;
private CheckBox mUmaCheckBox;
@Before
......@@ -425,6 +426,29 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupportTest {
renderWithPortraitAndLandscape(tosAndUmaFragment, "fre_tosanduma_nopolicy");
}
@Test
@SmallTest
@Feature({"RenderTest", "FirstRun"})
public void testRenderWithPolicy() throws Exception {
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);
CriteriaHelper.pollUiThread(
()
-> Criteria.checkThat(
mPrivacyDisclaimer.getVisibility(), Matchers.is(View.VISIBLE)));
renderWithPortraitAndLandscape(tosAndUmaFragment, "fre_tosanduma_withpolicy");
}
/**
* Launch chrome through custom tab and trigger first run.
*/
......@@ -462,11 +486,14 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupportTest {
mUmaCheckBox = mActivity.findViewById(R.id.send_report_checkbox);
mAcceptButton = mActivity.findViewById(R.id.terms_accept);
mLargeSpinner = 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;
CriteriaHelper.pollUiThread(
()
......@@ -480,11 +507,14 @@ public class TosAndUmaFirstRunFragmentWithEnterpriseSupportTest {
tosVisibility, mUmaCheckBox.getVisibility());
Assert.assertEquals("Visibility of accept button is different than the test setting.",
tosVisibility, mAcceptButton.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;
Assert.assertEquals(expectedExitCount, mExitCount);
CriteriaHelper.pollUiThread(
() -> Criteria.checkThat(mExitCount, Matchers.is(expectedExitCount)));
}
/**
......
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