Commit c1fb43c3 authored by Rohit Agarwal's avatar Rohit Agarwal Committed by Commit Bot

Add incognito interstitial package.

This CL adds the MVC elements of the incognito interstitial view and
also adds the functionality of the "Learn more" and "Continue" buttons.

This CL also adds Robolectric tests to tests the Incognito Interstitial
delegate.

The instrumentation tests would be followed up later.

The strings to the incognito interstitial would be added later.

Bug: 1120350, 1119280
Change-Id: I2c212029a6d440f95c074c04b068223dacaaba4b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2359032Reviewed-by: default avatarBoris Sazonov <bsazonov@chromium.org>
Reviewed-by: default avatarAlice Wang <aliceywang@chromium.org>
Commit-Queue: Rohit Agarwal <roagarwal@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804855}
parent 1ddd7b5e
......@@ -809,6 +809,11 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java",
"java/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotController.java",
"java/src/org/chromium/chrome/browser/incognito/IncognitoUtils.java",
"java/src/org/chromium/chrome/browser/incognito/interstitial/IncognitoInterstitialCoordinator.java",
"java/src/org/chromium/chrome/browser/incognito/interstitial/IncognitoInterstitialDelegate.java",
"java/src/org/chromium/chrome/browser/incognito/interstitial/IncognitoInterstitialMediator.java",
"java/src/org/chromium/chrome/browser/incognito/interstitial/IncognitoInterstitialProperties.java",
"java/src/org/chromium/chrome/browser/incognito/interstitial/IncognitoInterstitialViewBinder.java",
"java/src/org/chromium/chrome/browser/infobar/AdsBlockedInfoBar.java",
"java/src/org/chromium/chrome/browser/infobar/AutofillCreditCardFillingInfoBar.java",
"java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java",
......
......@@ -113,6 +113,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherTest.java",
"junit/src/org/chromium/chrome/browser/image_fetcher/InMemoryCachedImageFetcherTest.java",
"junit/src/org/chromium/chrome/browser/image_fetcher/NetworkImageFetcherTest.java",
"junit/src/org/chromium/chrome/browser/incognito/IncognitoInterstitialDelegateTest.java",
"junit/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotControllerTest.java",
"junit/src/org/chromium/chrome/browser/infobar/IPHInfoBarSupportTest.java",
"junit/src/org/chromium/chrome/browser/init/AsyncInitTaskRunnerTest.java",
......
// 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.incognito.interstitial;
import android.view.View;
import androidx.annotation.MainThread;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
/**
* The coordinator of the incognito interstitial along with IncognitoInterstitialDelegate are the
* only public class in this package.
*
* It is responsible for setting up the incognito interstitial view and model and it serves as an
* access point for users of this package.
*/
public class IncognitoInterstitialCoordinator {
/**
* TODO(crbug.com/1103262): Instead of passing a general View element pass an
* IncognitoInterstitialView.
*
* Constructs an IncognitoInterstitialCoordinator object.
*
* @param view The incognito interstitial view.
* @param incognitoInterstitialDelegate A delegate providing the functionality of the Incognito
* interstitial.
*/
@MainThread
public IncognitoInterstitialCoordinator(
View view, IncognitoInterstitialDelegate incognitoInterstitialDelegate) {
IncognitoInterstitialMediator mediator =
new IncognitoInterstitialMediator(incognitoInterstitialDelegate);
PropertyModelChangeProcessor.create(
mediator.getModel(), view, IncognitoInterstitialViewBinder::bindView);
}
}
// 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.incognito.interstitial;
import android.app.Activity;
import androidx.annotation.MainThread;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.help.HelpAndFeedback;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabCreator;
/**
* This class is responsible for the providing the functionality to the "Learn More" and "Continue"
* button in the Incognito interstitial.
*/
public class IncognitoInterstitialDelegate {
private final Activity mActivity;
private final TabCreator mIncognitoTabCreator;
private final HelpAndFeedback mHelpAndFeedback;
private final String mCurrentUrl;
public IncognitoInterstitialDelegate(Activity activity, TabCreator incognitoTabCreator,
HelpAndFeedback helpAndFeedback, String currentUrl) {
mActivity = activity;
mIncognitoTabCreator = incognitoTabCreator;
mHelpAndFeedback = helpAndFeedback;
mCurrentUrl = currentUrl;
}
/**
* Open the help centre article regarding Incognito usage.
*/
@MainThread
public void openLearnMorePage() {
ThreadUtils.assertOnUiThread();
mHelpAndFeedback.show(mActivity,
mActivity.getString(R.string.help_context_incognito_learn_more),
Profile.getLastUsedRegularProfile().getPrimaryOTRProfile(), null);
}
/**
* Navigates to |mCurrentUrl| in a new incognito tab.
*/
@MainThread
public void openCurrentUrlInIncognitoTab() {
// TODO(https://crbug.com/1120334): Add metrics to web sign-in flow.
ThreadUtils.assertOnUiThread();
mIncognitoTabCreator.launchUrl(mCurrentUrl, TabLaunchType.FROM_CHROME_UI);
}
}
\ No newline at end of file
// 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.incognito.interstitial;
import androidx.annotation.MainThread;
import org.chromium.ui.modelutil.PropertyModel;
/**
* The mediator of incognito interstitial handles all the signals from the outside world.
*
* It defines the business logic when the user clicks on "Learn more" or "Continue" button.
*/
class IncognitoInterstitialMediator {
private final PropertyModel mModel;
private final IncognitoInterstitialDelegate mIncognitoInterstitialDelegate;
IncognitoInterstitialMediator(IncognitoInterstitialDelegate incognitoInterstitialDelegate) {
mModel = IncognitoInterstitialProperties.createModel(
this::onLearnMoreClicked, this::onContinueClicked);
mIncognitoInterstitialDelegate = incognitoInterstitialDelegate;
}
PropertyModel getModel() {
return mModel;
}
/**
* Callback for {@link IncognitoInterstitialProperties#ON_LEARN_MORE_CLICKED}
*/
@MainThread
private void onLearnMoreClicked() {
mIncognitoInterstitialDelegate.openLearnMorePage();
}
/**
* Callback for {@link IncognitoInterstitialProperties#ON_CONTINUE_CLICKED}
*/
@MainThread
private void onContinueClicked() {
mIncognitoInterstitialDelegate.openCurrentUrlInIncognitoTab();
}
}
// 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.incognito.interstitial;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
/**
* Properties for account picker.
*/
class IncognitoInterstitialProperties {
private IncognitoInterstitialProperties() {}
// PropertyKey for the button |Learn more|
static final PropertyModel.ReadableObjectPropertyKey<Runnable> ON_LEARN_MORE_CLICKED =
new PropertyModel.ReadableObjectPropertyKey<>("on_learn_more_clicked");
// PropertyKey for the button |Continue|
static final PropertyModel.ReadableObjectPropertyKey<Runnable> ON_CONTINUE_CLICKED =
new PropertyModel.ReadableObjectPropertyKey<>("on_continue_clicked");
static final PropertyKey[] ALL_KEYS =
new PropertyKey[] {ON_LEARN_MORE_CLICKED, ON_CONTINUE_CLICKED};
static PropertyModel createModel(Runnable onLearnMoreClicked, Runnable onContinueClicked) {
return new PropertyModel.Builder(ALL_KEYS)
.with(ON_LEARN_MORE_CLICKED, onLearnMoreClicked)
.with(ON_CONTINUE_CLICKED, onContinueClicked)
.build();
}
}
// 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.incognito.interstitial;
import android.view.View;
import org.chromium.chrome.R;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
/**
* This class regroups the bindView util methods of the
* incognito interstitial.
*/
class IncognitoInterstitialViewBinder {
private IncognitoInterstitialViewBinder() {}
static void bindView(PropertyModel model, View view, PropertyKey propertyKey) {
if (propertyKey == IncognitoInterstitialProperties.ON_LEARN_MORE_CLICKED) {
getLearnMoreView(view).setOnClickListener(
v -> model.get(IncognitoInterstitialProperties.ON_LEARN_MORE_CLICKED).run());
} else if (propertyKey == IncognitoInterstitialProperties.ON_CONTINUE_CLICKED) {
getContinueButtonView(view).setOnClickListener(
v -> model.get(IncognitoInterstitialProperties.ON_CONTINUE_CLICKED).run());
} else {
throw new IllegalArgumentException(
"Cannot update the view for propertyKey: " + propertyKey);
}
}
// Necessary helper methods to return the subviews present inside the incognito
// interstitial |view|.
// TODO(crbug.com/1103262): Add these methods to the IncognitoInterstitialView once we implement
// it in future.
private static View getContinueButtonView(View view) {
return view.findViewById(R.id.incognito_interstitial_continue_button);
}
private static View getLearnMoreView(View view) {
return view.findViewById(R.id.incognito_interstitial_learn_more);
}
}
\ No newline at end of file
aliceywang@chromium.org
bsazonov@chromium.org
roagarwal@chromium.org
# TEAM: chrome-privacy-core@google.com
# COMPONENT: Privacy>Incognito
......@@ -10,6 +10,7 @@ import android.view.View;
import androidx.annotation.MainThread;
import androidx.annotation.VisibleForTesting;
import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialCoordinator;
import org.chromium.chrome.browser.signin.account_picker.AccountPickerCoordinator.AccountPickerAccessPoint;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
......@@ -47,6 +48,9 @@ public class AccountPickerBottomSheetCoordinator {
mView = new AccountPickerBottomSheetView(context, mAccountPickerBottomSheetMediator);
mAccountPickerCoordinator = new AccountPickerCoordinator(mView.getAccountListView(),
mAccountPickerBottomSheetMediator, null, AccountPickerAccessPoint.WEB);
IncognitoInterstitialCoordinator incognitoInterstitialCoordinator =
new IncognitoInterstitialCoordinator(mView.getIncognitoInterstitialView(),
accountPickerDelegate.getIncognitoInterstitialDelegate());
mBottomSheetController = bottomSheetController;
PropertyModelChangeProcessor.create(mAccountPickerBottomSheetMediator.getModel(), mView,
AccountPickerBottomSheetViewBinder::bind);
......
......@@ -81,6 +81,13 @@ class AccountPickerBottomSheetView implements BottomSheetContent {
return mAccountListView;
}
/**
* The incognito interstitial view when the user clicks on incognito mode option.
*/
View getIncognitoInterstitialView() {
return mIncognitoInterstitialView;
}
/**
* The selected account is visible when the account list is collapsed.
*/
......
......@@ -14,6 +14,8 @@ import androidx.annotation.Nullable;
import org.chromium.base.Callback;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.help.HelpAndFeedback;
import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialDelegate;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.signin.IdentityServicesProvider;
import org.chromium.chrome.browser.signin.SigninManager;
......@@ -45,6 +47,8 @@ public class AccountPickerDelegate implements WebSigninBridge.Listener {
public AccountPickerDelegate(WindowAndroid windowAndroid,
WebSigninBridge.Factory webSigninBridgeFactory, String continueUrl) {
mWindowAndroid = windowAndroid;
// TODO(crbug.com/1125459): Remove cast and pass the ChromeActiviy dependencies explicitly
// instead.
mChromeActivity = (ChromeActivity) mWindowAndroid.getActivity().get();
mTab = mChromeActivity.getActivityTab();
mWebSigninBridgeFactory = webSigninBridgeFactory;
......@@ -53,6 +57,17 @@ public class AccountPickerDelegate implements WebSigninBridge.Listener {
Profile.getLastUsedRegularProfile());
}
/**
* Creates and return the {@link IncognitoInterstitialDelegate}.
*/
public IncognitoInterstitialDelegate getIncognitoInterstitialDelegate() {
IncognitoInterstitialDelegate incognitoInterstitialDelegate =
new IncognitoInterstitialDelegate(mChromeActivity,
mChromeActivity.getTabCreator(/*incognito=*/true),
HelpAndFeedback.getInstance(), mTab.getUrlString());
return incognitoInterstitialDelegate;
}
/**
* Releases resources used by this class.
*/
......
// 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.incognito;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import androidx.test.filters.MediumTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.help.HelpAndFeedback;
import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialDelegate;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabCreator;
/**
* Roboelectric tests class for the incognito interstitial.
*/
@RunWith(BaseRobolectricTestRunner.class)
public class IncognitoInterstitialDelegateTest {
private static final String sIncognitoLearnMoreText = "dummy_chrome_incognito";
private static final String sContinueUrlPage = "dummy_url_string.com";
@Mock
private HelpAndFeedback mHelpAndFeedbackMock;
@Mock
private Profile mProfileMock;
@Mock
private Activity mActivityMock;
@Mock
private TabCreator mIncognitoTabCreatorMock;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mActivityMock.getString(R.string.help_context_incognito_learn_more))
.thenReturn(sIncognitoLearnMoreText);
Profile.setLastUsedProfileForTesting(mProfileMock);
mIncognitoInterstitialDelegate = new IncognitoInterstitialDelegate(
mActivityMock, mIncognitoTabCreatorMock, mHelpAndFeedbackMock, sContinueUrlPage);
}
@After
public void tearDown() {
Profile.setLastUsedProfileForTesting(null);
}
private IncognitoInterstitialDelegate mIncognitoInterstitialDelegate;
@Test
@MediumTest
public void testOpenLearnMorePage() {
mIncognitoInterstitialDelegate.openLearnMorePage();
verify(mHelpAndFeedbackMock)
.show(mActivityMock, sIncognitoLearnMoreText, mProfileMock.getPrimaryOTRProfile(),
null);
}
@Test
@MediumTest
public void testOpenCurrentUrlInIncognitoTab() {
mIncognitoInterstitialDelegate.openCurrentUrlInIncognitoTab();
verify(mIncognitoTabCreatorMock).launchUrl(sContinueUrlPage, TabLaunchType.FROM_CHROME_UI);
}
}
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