Skip to content

Commit

Permalink
Added controller for reader mode CPA
Browse files Browse the repository at this point in the history
This CL adds a button controller for reader mode as a contextual page
actions.

(cherry picked from commit acad206)

Bug: 1373898
Change-Id: I35aaa9fa719d333a7dcdad303211ef0d4b8a409b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3940208
Reviewed-by: Tommy Nyquist <[email protected]>
Reviewed-by: Shakti Sahu <[email protected]>
Commit-Queue: Salvador Guerrero Ramos <[email protected]>
Cr-Original-Commit-Position: refs/heads/main@{#1059371}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3962429
Cr-Commit-Position: refs/branch-heads/5359@{#58}
Cr-Branched-From: 27d3765-refs/heads/main@{#1058933}
  • Loading branch information
Salvador Guerrero authored and Chromium LUCI CQ committed Oct 18, 2022
1 parent 1327191 commit ee9dc0a
Show file tree
Hide file tree
Showing 14 changed files with 318 additions and 41 deletions.
1 change: 1 addition & 0 deletions chrome/android/chrome_java_sources.gni
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerTabUtils.java",
"java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerUIUtils.java",
"java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java",
"java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeToolbarButtonController.java",
"java/src/org/chromium/chrome/browser/dom_distiller/TabDistillabilityProvider.java",
"java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java",
"java/src/org/chromium/chrome/browser/download/DownloadBroadcastManagerImpl.java",
Expand Down
1 change: 1 addition & 0 deletions chrome/android/chrome_junit_test_java_sources.gni
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/directactions/GoBackDirectActionHandlerTest.java",
"junit/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutControllerTest.java",
"junit/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerTest.java",
"junit/src/org/chromium/chrome/browser/dom_distiller/ReaderModeToolbarButtonControllerTest.java",
"junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java",
"junit/src/org/chromium/chrome/browser/download/OfflineContentAvailabilityStatusProviderTest.java",
"junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2022 The Chromium Authors
// 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.dom_distiller;

import android.graphics.drawable.Drawable;
import android.view.View;

import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.BaseButtonDataProvider;
import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures.AdaptiveToolbarButtonVariant;
import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
import org.chromium.components.feature_engagement.FeatureConstants;
import org.chromium.ui.modaldialog.ModalDialogManager;

/**
* Responsible for providing UI resources for showing a reader mode button on toolbar.
*/
public class ReaderModeToolbarButtonController extends BaseButtonDataProvider {
/**
* Creates a new instance of {@code ReaderModeToolbarButtonController}.
*
* @param activeTabSupplier Supplier for the current active tab.
* @param modalDialogManager Modal dialog manager, used to disable the button when a dialog is
* visible. Can be null to disable this behavior.
* @param buttonDrawable Drawable for the button icon.
*/
public ReaderModeToolbarButtonController(Supplier<Tab> activeTabSupplier,
ModalDialogManager modalDialogManager, Drawable buttonDrawable) {
super(activeTabSupplier, modalDialogManager, buttonDrawable, R.string.reader_view_text_alt,
/* contentDescriptionResId= */ R.string.reader_mode_message_title,
/* supportsTinting= */ true, /* iphCommandBuilder= */ null,
AdaptiveToolbarButtonVariant.READER_MODE);
}

@Override
public void onClick(View view) {
Tab currentTab = mActiveTabSupplier.get();
if (currentTab == null) return;

ReaderModeManager readerModeManager =
currentTab.getUserDataHost().getUserData(ReaderModeManager.class);
if (readerModeManager == null) return;

readerModeManager.activateReaderMode();
}

@Override
protected IPHCommandBuilder getIphCommandBuilder(Tab tab) {
IPHCommandBuilder iphCommandBuilder = new IPHCommandBuilder(tab.getContext().getResources(),
FeatureConstants.CONTEXTUAL_PAGE_ACTIONS_QUIET_VARIANT,
/* stringId = */ R.string.reader_mode_message_title,
/* accessibilityStringId = */ R.string.reader_view_text_alt);
return iphCommandBuilder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package org.chromium.chrome.browser.share;

import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.View;

Expand Down Expand Up @@ -54,6 +55,7 @@ public ShareButtonController(Drawable buttonDrawable, ActivityTabProvider tabPro
Supplier<Tracker> trackerSupplier, ShareUtils shareUtils,
ModalDialogManager modalDialogManager, Runnable onShareRunnable) {
super(tabProvider, modalDialogManager, buttonDrawable, R.string.share,
/* actionChipLabelResId= */ Resources.ID_NULL,
/*supportsTinting=*/true,
/*iphCommandBuilder=*/null, AdaptiveToolbarButtonVariant.SHARE);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
import org.chromium.chrome.browser.crash.ChromePureJavaExceptionReporter;
import org.chromium.chrome.browser.directactions.DirectActionInitializer;
import org.chromium.chrome.browser.dom_distiller.ReaderModeToolbarButtonController;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.findinpage.FindToolbarManager;
import org.chromium.chrome.browser.findinpage.FindToolbarObserver;
Expand Down Expand Up @@ -1114,6 +1115,11 @@ protected void initializeToolbar() {
AppCompatResources.getDrawable(
mActivity, R.drawable.price_tracking_disabled),
mTabBookmarkerSupplier);
ReaderModeToolbarButtonController readerModeToolbarButtonController =
new ReaderModeToolbarButtonController(mActivityTabProvider,
mModalDialogManagerSupplier.get(),
AppCompatResources.getDrawable(
mActivity, R.drawable.infobar_mobile_friendly));
ShareButtonController shareButtonController = new ShareButtonController(
AppCompatResources.getDrawable(
mActivity, R.drawable.ic_toolbar_share_offset_24dp),
Expand Down Expand Up @@ -1161,6 +1167,8 @@ mActivityLifecycleDispatcher, new AdaptiveButtonActionMenuCoordinator(),
AdaptiveToolbarButtonVariant.VOICE, voiceToolbarButtonController);
adaptiveToolbarButtonController.addButtonVariant(
AdaptiveToolbarButtonVariant.PRICE_TRACKING, priceTrackingButtonController);
adaptiveToolbarButtonController.addButtonVariant(
AdaptiveToolbarButtonVariant.READER_MODE, readerModeToolbarButtonController);
mContextualPageActionController = new ContextualPageActionController(mProfileSupplier,
mActivityTabProvider, adaptiveToolbarButtonController,
()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2022 The Chromium Authors
// 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.dom_distiller;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;

import org.junit.Assert;
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.FeatureList;
import org.chromium.base.FeatureList.TestValues;
import org.chromium.base.UserDataHost;
import org.chromium.base.supplier.Supplier;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.ButtonData;
import org.chromium.ui.modaldialog.ModalDialogManager;

/** This class tests the behavior of the {@link ReaderModeToolbarButtonController}. */
@RunWith(BaseRobolectricTestRunner.class)
public class ReaderModeToolbarButtonControllerTest {
@Mock
private Tab mMockTab;
@Mock
private ReaderModeManager mMockReaderModeManager;
@Mock
private Supplier<Tab> mMockTabSupplier;
@Mock
private ModalDialogManager mMockModalDialogManager;
private UserDataHost mUserDataHost;
private TestValues mTestValues;

@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mUserDataHost = new UserDataHost();

Context mockContext = mock(Context.class);
Resources mockResources = mock(Resources.class);

doReturn(mockResources).when(mockContext).getResources();
doReturn(mockContext).when(mMockTab).getContext();
doReturn(mMockTab).when(mMockTabSupplier).get();
doReturn(mUserDataHost).when(mMockTab).getUserDataHost();
mUserDataHost.setUserData(ReaderModeManager.USER_DATA_KEY, mMockReaderModeManager);

mTestValues = new TestValues();
mTestValues.addFeatureFlagOverride(ChromeFeatureList.CONTEXTUAL_PAGE_ACTIONS, true);
mTestValues.addFeatureFlagOverride(
ChromeFeatureList.CONTEXTUAL_PAGE_ACTION_READER_MODE, true);
mTestValues.addFeatureFlagOverride(
ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2, true);

FeatureList.setTestValues(mTestValues);
}

private ReaderModeToolbarButtonController createController() {
return new ReaderModeToolbarButtonController(
mMockTabSupplier, mMockModalDialogManager, mock(Drawable.class));
}

@Test
public void testButtonClickEnablesReaderMode() {
ReaderModeToolbarButtonController controller = createController();

ButtonData readerModeButton = controller.get(mMockTab);
readerModeButton.getButtonSpec().getOnClickListener().onClick(null);

verify(mMockReaderModeManager).activateReaderMode();
}

@Test
public void testSwapButtonModeSetsIphCommandBuilder() {
ReaderModeToolbarButtonController controller = createController();

ButtonData readerModeButton = controller.get(mMockTab);

Assert.assertNotNull(readerModeButton.getButtonSpec().getIPHCommandBuilder());
}

@Test
public void testActionChipModeSetsNoIphCommandBuilder() {
// Set field trial param to use action chip variant.
mTestValues.addFeatureFlagOverride(
ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2, true);
mTestValues.addFieldTrialParamOverride(
ChromeFeatureList.CONTEXTUAL_PAGE_ACTIONS, "action_chip", "true");

ReaderModeToolbarButtonController controller = createController();

ButtonData readerModeButton = controller.get(mMockTab);

// IPH command builder should not be set on action chip variant.
Assert.assertNull(readerModeButton.getButtonSpec().getIPHCommandBuilder());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,15 @@

package org.chromium.chrome.browser.price_tracking;

import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.View;

import androidx.annotation.Nullable;

import org.chromium.base.FeatureList;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.bookmarks.TabBookmarker;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.BaseButtonDataProvider;
import org.chromium.chrome.browser.toolbar.ButtonData;
import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures;
import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures.AdaptiveToolbarButtonVariant;
import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
import org.chromium.components.feature_engagement.FeatureConstants;
Expand All @@ -37,38 +31,19 @@ public PriceTrackingButtonController(ObservableSupplier<Tab> tabSupplier,
Supplier<TabBookmarker> tabBookmarkerSupplier) {
super(tabSupplier, modalDialogManager, buttonDrawable,
R.string.enable_price_tracking_menu_item,
/* actionChipLabelResId= */ R.string.enable_price_tracking_menu_item,
/*supportsTinting=*/true, /*iphCommandBuilder*/ null,
AdaptiveToolbarButtonVariant.PRICE_TRACKING);
mTabBookmarkerSupplier = tabBookmarkerSupplier;
}

@Override
public ButtonData get(@Nullable Tab tab) {
maybeSetActionChipResourceId();
return super.get(tab);
}

private void maybeSetActionChipResourceId() {
if (FeatureList.isInitialized() && AdaptiveToolbarFeatures.shouldShowActionChip()) {
// OptionalButtonCoordinator may choose to not show this action chip. It uses feature
// engagement to rate limit this animation.
mButtonData.updateActionChipResourceId(R.string.enable_price_tracking_menu_item);
} else {
mButtonData.updateActionChipResourceId(Resources.ID_NULL);
}
}

@Override
public void onClick(View view) {
mTabBookmarkerSupplier.get().startOrModifyPriceTracking(mActiveTabSupplier.get());
}

@Override
protected IPHCommandBuilder getIphCommandBuilder(Tab tab) {
if (AdaptiveToolbarFeatures.shouldShowActionChip()) {
return null;
}

IPHCommandBuilder iphCommandBuilder = new IPHCommandBuilder(tab.getContext().getResources(),
FeatureConstants.CONTEXTUAL_PAGE_ACTIONS_QUIET_VARIANT,
/* stringId = */ R.string.iph_price_tracking_menu_item,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package org.chromium.chrome.browser.toolbar;

import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.View.OnClickListener;
Expand Down Expand Up @@ -51,8 +52,8 @@ public abstract class BaseButtonDataProvider implements ButtonDataProvider, OnCl
*/
public BaseButtonDataProvider(Supplier<Tab> activeTabSupplier,
@Nullable ModalDialogManager modalDialogManager, Drawable buttonDrawable,
@StringRes int contentDescriptionResId, boolean supportsTinting,
@Nullable IPHCommandBuilder iphCommandBuilder,
@StringRes int contentDescriptionResId, @StringRes int actionChipLabelResId,
boolean supportsTinting, @Nullable IPHCommandBuilder iphCommandBuilder,
@AdaptiveToolbarButtonVariant int adaptiveButtonVariant) {
mActiveTabSupplier = activeTabSupplier;
mModalDialogManager = modalDialogManager;
Expand All @@ -73,8 +74,14 @@ public void onLastDialogDismissed() {
mModalDialogManager.addObserver(mModalDialogObserver);
}

if (!AdaptiveToolbarFeatures.isDynamicAction(adaptiveButtonVariant)) {
assert actionChipLabelResId
== Resources.ID_NULL : "Action chip should only be used on dynamic actions";
}

mButtonData = new ButtonDataImpl(/*canShow=*/false, buttonDrawable,
/* onClickListener= */ this, contentDescriptionResId, supportsTinting,
/* onClickListener= */ this, contentDescriptionResId, actionChipLabelResId,
supportsTinting,
/* iphCommandBuilder= */ iphCommandBuilder, /*isEnabled=*/true,
adaptiveButtonVariant);
}
Expand Down Expand Up @@ -107,8 +114,8 @@ protected void notifyObservers(boolean hint) {
*/
private void maybeSetIphCommandBuilder(Tab tab) {
if (mButtonData.getButtonSpec().getIPHCommandBuilder() != null || tab == null
|| !FeatureList.isInitialized()
|| !AdaptiveToolbarFeatures.isCustomizationEnabled()) {
|| !FeatureList.isInitialized() || !AdaptiveToolbarFeatures.isCustomizationEnabled()
|| AdaptiveToolbarFeatures.shouldShowActionChip()) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,21 @@ public ButtonDataImpl(boolean canShow, @NonNull Drawable drawable,
@NonNull OnClickListener onClickListener, int contentDescriptionResId,
boolean supportsTinting, @Nullable IPHCommandBuilder iphCommandBuilder,
boolean isEnabled, @AdaptiveToolbarButtonVariant int buttonVariant) {
this(canShow, drawable, onClickListener, contentDescriptionResId,
/*actionChipLabelResId= */ Resources.ID_NULL, supportsTinting, iphCommandBuilder,
isEnabled, buttonVariant);
}

public ButtonDataImpl(boolean canShow, @NonNull Drawable drawable,
@NonNull OnClickListener onClickListener, @StringRes int contentDescriptionResId,
@StringRes int actionChipLabelResId, boolean supportsTinting,
@Nullable IPHCommandBuilder iphCommandBuilder, boolean isEnabled,
@AdaptiveToolbarButtonVariant int buttonVariant) {
mCanShow = canShow;
mIsEnabled = isEnabled;
mButtonSpec = new ButtonSpec(drawable, onClickListener, /*onLongClickListener=*/null,
contentDescriptionResId, supportsTinting, iphCommandBuilder, buttonVariant,
/* actionChipLabelResId= */ Resources.ID_NULL);
actionChipLabelResId);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package org.chromium.chrome.browser.toolbar;

import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.View;

Expand Down Expand Up @@ -62,6 +63,7 @@ public VoiceToolbarButtonController(Drawable buttonDrawable, Supplier<Tab> activ
VoiceSearchDelegate voiceSearchDelegate) {
super(activeTabSupplier, modalDialogManager, buttonDrawable,
R.string.accessibility_toolbar_btn_mic,
/* actionChipLabelResId= */ Resources.ID_NULL,
/* supportsTinting= */ true, /* iphCommandBuilder= */ null,
AdaptiveToolbarButtonVariant.VOICE);
mTrackerSupplier = trackerSupplier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.View;

Expand Down Expand Up @@ -97,7 +98,7 @@ public OptionalNewTabButtonController(Context context, Drawable buttonDrawable,
Supplier<TabCreatorManager> tabCreatorManagerSupplier, Supplier<Tab> activeTabSupplier,
Supplier<Tracker> trackerSupplier) {
super(activeTabSupplier, /* modalDialogManager= */ null, buttonDrawable,
R.string.button_new_tab,
R.string.button_new_tab, /* actionChipLabelResId= */ Resources.ID_NULL,
/*supportsTinting= */ true, /* iphCommandBuilder= */ null,
AdaptiveToolbarButtonVariant.NEW_TAB);
setShouldShowOnIncognitoTabs(true);
Expand Down
Loading

0 comments on commit ee9dc0a

Please sign in to comment.