Commit cac85ac0 authored by Vincent Boisselle's avatar Vincent Boisselle Committed by Commit Bot

Conditional logging in Feed V1

Change-Id: I4378c135745eff9693a7d013d423a6f018dee649
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2440907
Commit-Queue: Vincent Boisselle <vincb@google.com>
Reviewed-by: default avatarHenrique Nakashima <hnakashima@chromium.org>
Reviewed-by: default avatarDan H <harringtond@chromium.org>
Cr-Commit-Position: refs/heads/master@{#813909}
parent 02b02434
......@@ -14,6 +14,8 @@ import java.util.List;
/** Allows Stream to notify the Feed library of actions taken */
public interface ActionManager extends ViewActionManager {
public static enum UploadActionType { MISC, CLICK, VIEW }
/**
* Dismiss content for the content ID in the session, along with executing the provided stream
* data operations on the session.
......@@ -41,12 +43,13 @@ public interface ActionManager extends ViewActionManager {
* Issues a request to record a set of actions, with the consumer being called back with the
* resulting {@link ConsistencyToken}.
*/
void createAndUploadAction(String contentId, ActionPayload payload);
void createAndUploadAction(
String contentId, ActionPayload payload, UploadActionType actionType);
/**
* Issues a request to record a single action and store it for future upload.
*/
void createAndStoreAction(String contentId, ActionPayload payload);
void createAndStoreAction(String contentId, ActionPayload payload, UploadActionType actionType);
/**
* Issues a request to record a set of action and update the url with consistency token with the
......@@ -54,4 +57,10 @@ public interface ActionManager extends ViewActionManager {
*/
void uploadAllActionsAndUpdateUrl(
String url, String consistencyTokenQueryParamName, Consumer<String> consumer);
/**
* Sets the bit that determines whether clicks and views can be uploaded when the notice card is
* present.
*/
void setCanUploadClicksAndViewsWhenNoticeCardIsPresent(boolean canUploadClicksAndViews);
}
......@@ -85,10 +85,14 @@ import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.scroll.Sc
import org.chromium.chrome.browser.feed.library.sharedstream.scroll.ScrollListenerNotifier;
import org.chromium.chrome.browser.feed.shared.stream.Header;
import org.chromium.chrome.browser.feed.shared.stream.Stream;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext;
import org.chromium.components.feed.core.proto.libraries.basicstream.internal.StreamSavedInstanceStateProto.StreamSavedInstanceState;
import org.chromium.components.feed.core.proto.libraries.sharedstream.ScrollStateProto.ScrollState;
import org.chromium.components.feed.core.proto.libraries.sharedstream.UiRefreshReasonProto.UiRefreshReason;
import org.chromium.components.user_prefs.UserPrefs;
import java.util.List;
......@@ -304,6 +308,7 @@ public class BasicStream implements Stream, ModelProviderObserver, OnLayoutChang
mStreamOfflineMonitor.onDestroy();
mUiSessionRequestLogger.onDestroy();
mActionManager.setViewport(null);
mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false);
mIsDestroyed = true;
}
......@@ -511,9 +516,19 @@ public class BasicStream implements Stream, ModelProviderObserver, OnLayoutChang
mRecyclerView.addOnLayoutChangeListener(this);
mActionManager.setViewport(mRecyclerView);
mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(canUpload());
addScrollListener(mActionManager.getScrollListener());
}
private boolean canUpload() {
if (ChromeFeatureList.isEnabled(
ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD)) {
return UserPrefs.get(Profile.getLastUsedRegularProfile())
.getBoolean(Pref.HAS_REACHED_CLICK_AND_VIEW_ACTIONS_UPLOAD_CONDITIONS);
}
return true;
}
private void updateAdapterAfterSessionStart(ModelProvider modelProvider) {
StreamDriver newStreamDriver = createStreamDriver(mActionApi, mActionManager,
mActionParserFactory, modelProvider, mThreadUtils, mClock, mConfiguration, mContext,
......
......@@ -130,7 +130,8 @@ public class StreamActionApiImpl implements StreamActionApi {
@Override
public void onDismissCommitted() {
dismiss(dataOperations);
mActionManager.createAndUploadAction(mContentId, payload);
mActionManager.createAndUploadAction(
mContentId, payload, ActionManager.UploadActionType.MISC);
mBasicLoggingApi.onNotInterestedIn(
interestType, mContentLoggingData.get(), /* wasCommitted = */ true);
}
......@@ -142,7 +143,8 @@ public class StreamActionApiImpl implements StreamActionApi {
public void handleBlockContent(
List<StreamDataOperation> dataOperations, ActionPayload payload) {
dismiss(dataOperations);
mActionManager.createAndUploadAction(mContentId, payload);
mActionManager.createAndUploadAction(
mContentId, payload, ActionManager.UploadActionType.MISC);
}
@Override
......@@ -164,7 +166,8 @@ public class StreamActionApiImpl implements StreamActionApi {
public void onDismissCommitted() {
dismissLocal(contentId, dataOperations);
dismiss(dataOperations);
mActionManager.createAndUploadAction(contentId, payload);
mActionManager.createAndUploadAction(
contentId, payload, ActionManager.UploadActionType.MISC);
mBasicLoggingApi.onContentDismissed(
mContentLoggingData.get(), /* wasCommitted = */ true);
}
......@@ -334,7 +337,8 @@ public class StreamActionApiImpl implements StreamActionApi {
@Override
public void reportClickAction(String contentId, ActionPayload payload) {
if (FeedFeatures.isReportingUserActions()) {
mActionManager.createAndUploadAction(contentId, payload);
mActionManager.createAndUploadAction(
contentId, payload, ActionManager.UploadActionType.CLICK);
}
}
......
......@@ -36,9 +36,12 @@ import org.chromium.chrome.browser.feed.shared.FeedFeatures;
import org.chromium.chrome.browser.feed.shared.stream.Stream.ScrollListener;
import org.chromium.chrome.browser.feed.shared.stream.Stream.ScrollListener.ScrollState;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation;
import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamUploadableAction;
import org.chromium.components.feed.core.proto.wire.ActionPayloadProto.ActionPayload;
import org.chromium.components.user_prefs.UserPrefs;
import java.util.HashMap;
import java.util.HashSet;
......@@ -88,6 +91,8 @@ public class FeedActionManagerImpl implements ActionManager {
private final double mViewportCoverageThreshold;
private final long mViewDurationMsThreshold;
private boolean mCanUploadClicksAndViewsWhenNoticePresent;
FeedActionManagerImpl(Store store, ThreadUtils threadUtils, TaskQueue taskQueue,
MainThreadRunner mainThreadRunner, ViewHandler viewHandler, Clock clock,
BasicLoggingApi basicLoggingApi) {
......@@ -120,6 +125,11 @@ public class FeedActionManagerImpl implements ActionManager {
mFeedSessionManager = feedSessionManager;
}
@Override
public void setCanUploadClicksAndViewsWhenNoticeCardIsPresent(boolean canUploadClicksAndViews) {
mCanUploadClicksAndViewsWhenNoticePresent = canUploadClicksAndViews;
}
@Override
public void dismissLocal(List<String> contentIds,
List<StreamDataOperation> streamDataOperations, @Nullable String sessionId) {
......@@ -142,7 +152,13 @@ public class FeedActionManagerImpl implements ActionManager {
}
@Override
public void createAndUploadAction(String contentId, ActionPayload payload) {
public void createAndUploadAction(
String contentId, ActionPayload payload, ActionManager.UploadActionType type) {
// Don't upload click actions when logging is disabled.
if (!canUploadClicksAndViews() && type == ActionManager.UploadActionType.CLICK) {
return;
}
mTaskQueue.execute(Task.CREATE_AND_UPLOAD, TaskType.BACKGROUND, () -> {
HashSet<StreamUploadableAction> actionSet = new HashSet<>();
long currentTime = TimeUnit.MILLISECONDS.toSeconds(mClock.currentTimeMillis());
......@@ -156,7 +172,13 @@ public class FeedActionManagerImpl implements ActionManager {
}
@Override
public void createAndStoreAction(String contentId, ActionPayload payload) {
public void createAndStoreAction(
String contentId, ActionPayload payload, ActionManager.UploadActionType type) {
// Don't store click actions when logging is disabled.
if (!canUploadClicksAndViews() && type == ActionManager.UploadActionType.CLICK) {
return;
}
mTaskQueue.execute(Task.CREATE_AND_STORE, TaskType.BACKGROUND, () -> {
long currentTime = TimeUnit.MILLISECONDS.toSeconds(mClock.currentTimeMillis());
StreamUploadableAction action = StreamUploadableAction.newBuilder()
......@@ -355,6 +377,11 @@ public class FeedActionManagerImpl implements ActionManager {
}
private void reportViewActions(Runnable doneCallback) {
// Don't report when logging is disabled.
if (!canUploadClicksAndViews()) {
return;
}
Set<StreamUploadableAction> actions = new HashSet<>();
if (FeedFeatures.isReportingUserActions()) {
Iterator<Map.Entry<String, ViewActionData>> entryIterator =
......@@ -476,4 +503,10 @@ public class FeedActionManagerImpl implements ActionManager {
return new ViewActionData(actionPayload, 0L, false);
}
}
private boolean canUploadClicksAndViews() {
boolean wasNoticePresent = UserPrefs.get(Profile.getLastUsedRegularProfile())
.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD);
return mCanUploadClicksAndViewsWhenNoticePresent || !wasNoticePresent;
}
}
......@@ -42,6 +42,7 @@ import org.chromium.chrome.browser.feed.library.common.time.TimingUtils;
import org.chromium.chrome.browser.feed.library.common.time.TimingUtils.ElapsedTimeTracker;
import org.chromium.chrome.browser.feed.library.feedrequestmanager.internal.Utils;
import org.chromium.chrome.browser.feed.shared.FeedFeatures;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.profiles.ProfileManager;
import org.chromium.chrome.browser.signin.IdentityServicesProvider;
......@@ -66,6 +67,7 @@ import org.chromium.components.feed.core.proto.wire.SemanticPropertiesProto.Sema
import org.chromium.components.feed.core.proto.wire.VersionProto.Version;
import org.chromium.components.feed.core.proto.wire.VersionProto.Version.Architecture;
import org.chromium.components.feed.core.proto.wire.VersionProto.Version.BuildType;
import org.chromium.components.user_prefs.UserPrefs;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
......@@ -127,7 +129,7 @@ public class FeedRequestManagerImpl implements FeedRequestManager {
RequestBuilder request = newDefaultRequest(RequestReason.MANUAL_CONTINUATION)
.setPageToken(streamToken.getNextPageToken())
.setConsistencyToken(token);
executeRequest(request, consumer);
executeRequest(request, consumer, false);
timeTracker.stop(
"task", "FeedRequestManagerImpl LoadMore", "token", streamToken.getNextPageToken());
}
......@@ -147,9 +149,9 @@ public class FeedRequestManagerImpl implements FeedRequestManager {
// This will make a new request, it should invalidate the existing head to delay
// everything until the response is obtained.
mTaskQueue.execute(Task.REQUEST_MANAGER_TRIGGER_REFRESH, TaskType.HEAD_INVALIDATE,
() -> executeRequest(request, consumer));
() -> executeRequest(request, consumer, true));
} else {
executeRequest(request, consumer);
executeRequest(request, consumer, true);
}
}
......@@ -193,7 +195,8 @@ public class FeedRequestManagerImpl implements FeedRequestManager {
return false;
}
private void executeRequest(RequestBuilder requestBuilder, Consumer<Result<Model>> consumer) {
private void executeRequest(RequestBuilder requestBuilder, Consumer<Result<Model>> consumer,
boolean isRefreshRequest) {
mThreadUtils.checkNotMainThread();
// Do not include Dismiss actions in the FeedQuery request for signed in users.
// Dismiss actions for signed in users are uploaded via the ActionsUpload endpoint.
......@@ -213,12 +216,12 @@ public class FeedRequestManagerImpl implements FeedRequestManager {
FeatureName.CARD_MENU_TOOLTIP, (wouldTrigger) -> {
mTaskQueue.execute(Task.SEND_REQUEST, TaskType.IMMEDIATE, () -> {
requestBuilder.setCardMenuTooltipWouldTrigger(wouldTrigger);
sendRequest(requestBuilder, consumer);
sendRequest(requestBuilder, consumer, isRefreshRequest);
});
});
});
} else {
sendRequest(requestBuilder, consumer);
sendRequest(requestBuilder, consumer, isRefreshRequest);
}
}
......@@ -227,7 +230,8 @@ public class FeedRequestManagerImpl implements FeedRequestManager {
|| reason == FeedQuery.RequestReason.WITH_CONTENT);
}
private void sendRequest(RequestBuilder requestBuilder, Consumer<Result<Model>> consumer) {
private void sendRequest(RequestBuilder requestBuilder, Consumer<Result<Model>> consumer,
boolean isRefreshRequest) {
mThreadUtils.checkNotMainThread();
String endpoint = mConfiguration.getValueOrDefault(ConfigKey.FEED_SERVER_ENDPOINT, "");
@HttpMethod
......@@ -261,12 +265,12 @@ public class FeedRequestManagerImpl implements FeedRequestManager {
"FeedRequestManagerImpl consumer", () -> consumer.accept(Result.failure()));
return;
}
handleResponseBytes(input.getResponseBody(), consumer);
handleResponseBytes(input.getResponseBody(), consumer, isRefreshRequest);
});
}
private void handleResponseBytes(
final byte[] responseBytes, final Consumer<Result<Model>> consumer) {
private void handleResponseBytes(final byte[] responseBytes,
final Consumer<Result<Model>> consumer, boolean isRefreshRequest) {
mTaskQueue.execute(Task.HANDLE_RESPONSE_BYTES, TaskType.IMMEDIATE, () -> {
Response response;
boolean isLengthPrefixed = mConfiguration.getValueOrDefault(
......@@ -282,17 +286,28 @@ public class FeedRequestManagerImpl implements FeedRequestManager {
"FeedRequestManagerImpl consumer", () -> consumer.accept(Result.failure()));
return;
}
logServerCapabilities(response);
logServerCapabilities(response, isRefreshRequest);
mMainThreadRunner.execute("FeedRequestManagerImpl consumer",
() -> consumer.accept(mProtocolAdapter.createModel(response)));
});
}
private static void logServerCapabilities(Response response) {
private void logServerCapabilities(Response response, boolean isRefreshRequest) {
FeedResponse feedResponse = response.getExtension(FeedResponse.feedResponse);
List<Capability> capabilities = feedResponse.getServerCapabilitiesList();
RecordHistogram.recordBooleanHistogram("ContentSuggestions.Feed.NoticeCardFulfilled",
capabilities.contains(Capability.REPORT_FEED_USER_ACTIONS_NOTICE_CARD));
if (isRefreshRequest) {
mMainThreadRunner.execute("Update notice card pref",
()
-> updateNoticeCardPref(capabilities.contains(
Capability.REPORT_FEED_USER_ACTIONS_NOTICE_CARD)));
}
}
private void updateNoticeCardPref(boolean hasNoticeCard) {
UserPrefs.get(Profile.getLastUsedRegularProfile())
.setBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD, hasNoticeCard);
}
private static final class RequestBuilder {
......
......@@ -24,9 +24,12 @@ import org.chromium.chrome.browser.feed.library.api.host.logging.Task;
import org.chromium.chrome.browser.feed.library.api.host.logging.ZeroStateShowReason;
import org.chromium.chrome.browser.feed.library.common.time.Clock;
import org.chromium.chrome.browser.feed.shared.stream.Stream.ScrollListener;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.ntp.NewTabPageUma;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.feed.core.proto.ui.action.FeedActionProto;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.ui.mojom.WindowOpenDisposition;
import java.util.List;
......@@ -39,6 +42,8 @@ import java.util.concurrent.TimeUnit;
@JNINamespace("feed")
public class FeedLoggingBridge implements BasicLoggingApi {
private static final String TAG = "FeedLoggingBridge";
private static final int SHOWN_INDEX_THRESHOLD = 2;
private long mNativeFeedLoggingBridge;
private static final int MIN_SCROLL_THRESHOLD_DP = 160; // one inch.
private static final long VISIT_TIME_THRESHOLD = 1000 * 60 * 5; // 5 min in ms.
......@@ -47,6 +52,7 @@ public class FeedLoggingBridge implements BasicLoggingApi {
private boolean mScrolledReported;
private long mVisitStartTime;
private Clock mClock;
private boolean mHasReachedShownIndexesThreshold;
// This enum is used for UMA, don't move or reassign these numbers.
public @interface FeedEngagementType {
......@@ -71,6 +77,10 @@ public class FeedLoggingBridge implements BasicLoggingApi {
mScrolledReported = false;
mClock = clock;
mVisitStartTime = 0;
// Set the initial value to true when the conditional logging feature is disabled because
// the threshold isn't needed in that case.
mHasReachedShownIndexesThreshold = !ChromeFeatureList.isEnabled(
ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD);
}
/** Cleans up native half of this bridge. */
......@@ -85,6 +95,8 @@ public class FeedLoggingBridge implements BasicLoggingApi {
@Override
public void onContentViewed(ContentLoggingData data) {
onShownSlice(data.getPositionInStream());
// Bridge could have been destroyed for policy when this is called.
// See https://crbug.com/901414.
if (mNativeFeedLoggingBridge == 0) return;
......@@ -96,6 +108,18 @@ public class FeedLoggingBridge implements BasicLoggingApi {
data.isAvailableOffline());
}
private void onShownSlice(int index) {
if (mHasReachedShownIndexesThreshold) {
return;
}
if (index + 1 >= SHOWN_INDEX_THRESHOLD) {
mHasReachedShownIndexesThreshold = true;
UserPrefs.get(Profile.getLastUsedRegularProfile())
.setBoolean(Pref.HAS_REACHED_CLICK_AND_VIEW_ACTIONS_UPLOAD_CONDITIONS, true);
}
}
@Override
public void onContentDismissed(ContentLoggingData data, boolean wasCommitted) {
// Bridge could have been destroyed for policy when this is called.
......
......@@ -34,7 +34,9 @@ import androidx.recyclerview.widget.RecyclerView;
import com.google.protobuf.InvalidProtocolBufferException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.robolectric.Robolectric;
......@@ -42,6 +44,8 @@ import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.chromium.base.Consumer;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.feed.library.api.client.knowncontent.ContentMetadata;
import org.chromium.chrome.browser.feed.library.api.client.knowncontent.KnownContent;
import org.chromium.chrome.browser.feed.library.api.host.action.ActionApi;
......@@ -94,12 +98,18 @@ import org.chromium.chrome.browser.feed.library.testing.shadows.ShadowRecycledVi
import org.chromium.chrome.browser.feed.shared.stream.Header;
import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener;
import org.chromium.chrome.browser.feed.shared.stream.Stream.ScrollListener;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext;
import org.chromium.components.feed.core.proto.libraries.basicstream.internal.StreamSavedInstanceStateProto.StreamSavedInstanceState;
import org.chromium.components.feed.core.proto.libraries.sharedstream.ScrollStateProto.ScrollState;
import org.chromium.components.feed.core.proto.libraries.sharedstream.UiRefreshReasonProto.UiRefreshReason;
import org.chromium.components.feed.core.proto.libraries.sharedstream.UiRefreshReasonProto.UiRefreshReason.Reason;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.components.user_prefs.UserPrefsJni;
import org.chromium.testing.local.LocalRobolectricTestRunner;
import java.util.ArrayList;
......@@ -111,6 +121,7 @@ import java.util.Set;
/** Tests for {@link BasicStream}. */
@RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE, shadows = {ShadowRecycledViewPool.class})
@Features.DisableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD)
public class BasicStreamTest {
private static final int START_PADDING = 1;
private static final int END_PADDING = 2;
......@@ -137,6 +148,12 @@ public class BasicStreamTest {
.put(ConfigKey.SPINNER_MINIMUM_SHOW_TIME_MS, SPINNER_MINIMUM_SHOW_TIME_MS)
.build();
@Rule
public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor();
@Rule
public JniMocker mocker = new JniMocker();
@Mock
private StreamConfiguration mStreamConfiguration;
@Mock
......@@ -173,6 +190,12 @@ public class BasicStreamTest {
private TooltipApi mTooltipApi;
@Mock
private ActionManager mActionManager;
@Mock
private UserPrefs.Natives mUserPrefsJniMock;
@Mock
private Profile mProfile;
@Mock
private PrefService mPrefService;
private FakeFeedKnownContent mFakeFeedKnownContent;
private LinearLayoutManagerWithFakePositioning mLayoutManager;
......@@ -186,6 +209,12 @@ public class BasicStreamTest {
public void setUp() {
initMocks(this);
mocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock);
Profile.setLastUsedProfileForTesting(mProfile);
when(mUserPrefsJniMock.get(mProfile)).thenReturn(mPrefService);
when(mPrefService.getBoolean(Pref.HAS_REACHED_CLICK_AND_VIEW_ACTIONS_UPLOAD_CONDITIONS))
.thenReturn(true);
mFakeFeedKnownContent = new FakeFeedKnownContent();
mHeaders = new ArrayList<>();
mHeaders.add(mock(Header.class));
......@@ -221,6 +250,12 @@ public class BasicStreamTest {
mBasicStream.onCreate(null);
}
@Test
@Features.EnableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD)
public void testOnCreate_setReachedUploadConditionsBitInActionManager_whenFeatureEnabled() {
verify(mActionManager, times(1)).setCanUploadClicksAndViewsWhenNoticeCardIsPresent(true);
}
@Test
public void testRecyclerViewSetup() {
assertThat(getStreamRecyclerView().getId()).isEqualTo(R.id.feed_stream_recycler_view);
......
......@@ -253,7 +253,9 @@ public class StreamActionApiImplTest {
mStreamActionApi.handleBlockContent(streamDataOperations, ACTION_PAYLOAD);
verify(mActionManager).dismiss(streamDataOperations, SESSION_ID);
verify(mActionManager).createAndUploadAction(CONTENT_ID, ACTION_PAYLOAD);
verify(mActionManager)
.createAndUploadAction(
CONTENT_ID, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC);
}
@Test
......@@ -299,7 +301,9 @@ public class StreamActionApiImplTest {
String contentId = "contentId";
mStreamActionApi.reportClickAction(contentId, ACTION_PAYLOAD);
verify(mActionManager).createAndUploadAction(contentId, ACTION_PAYLOAD);
verify(mActionManager)
.createAndUploadAction(
contentId, ACTION_PAYLOAD, ActionManager.UploadActionType.CLICK);
}
@Test
......@@ -308,7 +312,8 @@ public class StreamActionApiImplTest {
mStreamActionApi.reportClickAction("contentId", ACTION_PAYLOAD);
verify(mActionManager, never())
.createAndUploadAction(anyString(), any(ActionPayload.class));
.createAndUploadAction(anyString(), any(ActionPayload.class),
any(ActionManager.UploadActionType.class));
}
@Test
......@@ -611,7 +616,9 @@ public class StreamActionApiImplTest {
ImmutableList.of(CONTENT_ID), streamDataOperations, SESSION_ID);
verify(mBasicLoggingApi)
.onContentDismissed(mContentLoggingData, /*wasCommitted =*/true);
verify(mActionManager).createAndUploadAction(CONTENT_ID, ACTION_PAYLOAD);
verify(mActionManager)
.createAndUploadAction(
CONTENT_ID, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC);
break;
case DISMISS_LOCAL:
verify(mActionManager)
......@@ -625,7 +632,9 @@ public class StreamActionApiImplTest {
verify(mBasicLoggingApi)
.onNotInterestedIn(
INTEREST_TYPE, mContentLoggingData, /*wasCommitted =*/true);
verify(mActionManager).createAndUploadAction(CONTENT_ID, ACTION_PAYLOAD);
verify(mActionManager)
.createAndUploadAction(
CONTENT_ID, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC);
break;
default:
break;
......
......@@ -32,7 +32,9 @@ import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import org.chromium.base.Consumer;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.feed.library.api.common.MutationContext;
import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager;
import org.chromium.chrome.browser.feed.library.api.internal.common.Model;
import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager;
import org.chromium.chrome.browser.feed.library.api.internal.store.LocalActionMutation;
......@@ -46,6 +48,8 @@ import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTh
import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock;
import org.chromium.chrome.browser.feed.v1.FeedLoggingBridge;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation;
import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure;
......@@ -53,6 +57,9 @@ import org.chromium.components.feed.core.proto.libraries.api.internal.StreamData
import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamUploadableAction;
import org.chromium.components.feed.core.proto.wire.ActionPayloadProto.ActionPayload;
import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.components.user_prefs.UserPrefsJni;
import org.chromium.testing.local.LocalRobolectricTestRunner;
import java.time.Duration;
......@@ -96,6 +103,9 @@ public class FeedActionManagerImplTest {
@Rule
public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor();
@Rule
public JniMocker mocker = new JniMocker();
@Mock
private FeedSessionManager mFeedSessionManager;
@Mock
......@@ -110,6 +120,13 @@ public class FeedActionManagerImplTest {
private FeedLoggingBridge mFeedLoggingBridge;
@Mock
private Runnable mStoreViewActionsRunnable;
@Mock
private UserPrefs.Natives mUserPrefsJniMock;
@Mock
private Profile mProfile;
@Mock
private PrefService mPrefService;
@Captor
private ArgumentCaptor<Integer> mActionTypeCaptor;
@Captor
......@@ -132,6 +149,11 @@ public class FeedActionManagerImplTest {
@Before
public void setUp() throws Exception {
initMocks(this);
mocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock);
Profile.setLastUsedProfileForTesting(mProfile);
when(mUserPrefsJniMock.get(mProfile)).thenReturn(mPrefService);
mActionManager = new FeedActionManagerImpl(mStore, mFakeThreadUtils, getTaskQueue(),
mFakeMainThreadRunner, new TestViewHandler(), mFakeClock, mFeedLoggingBridge);
mActionManager.initialize(mFeedSessionManager);
......@@ -150,6 +172,7 @@ public class FeedActionManagerImplTest {
mViewport = new TestView();
mViewport.setRectOnScreen(VIEWPORT_RECT);
mActionManager.setViewport(mViewport);
mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false);
}
@Test
......@@ -237,9 +260,26 @@ public class FeedActionManagerImplTest {
}
@Test
public void triggerCreateAndUploadAction() throws Exception {
public void triggerCreateAndUploadAction_whenUploadDisabled_byCantUploadWithNotice()
throws Exception {
mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false);
when(mPrefService.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD)).thenReturn(true);
mFakeClock.set(DEFAULT_TIME);
mActionManager.createAndUploadAction(
CONTENT_ID_STRING, ACTION_PAYLOAD, ActionManager.UploadActionType.CLICK);
verify(mFeedSessionManager, never()).triggerUploadActions(mActionCaptor.capture());
}
@Test
public void triggerCreateAndUploadAction_whenUploadEnabled_byCanUploadWithNotice()
throws Exception {
mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(true);
when(mPrefService.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD)).thenReturn(true);
mFakeClock.set(DEFAULT_TIME);
mActionManager.createAndUploadAction(CONTENT_ID_STRING, ACTION_PAYLOAD);
mActionManager.createAndUploadAction(
CONTENT_ID_STRING, ACTION_PAYLOAD, ActionManager.UploadActionType.CLICK);
verify(mFeedSessionManager).triggerUploadActions(mActionCaptor.capture());
StreamUploadableAction action =
(StreamUploadableAction) mActionCaptor.getValue().toArray()[0];
......@@ -249,16 +289,35 @@ public class FeedActionManagerImplTest {
}
@Test
public void triggerCreateAndStoreAction() throws Exception {
public void triggerCreateAndUploadAction_whenUploadEnabled_byNoClickAction() throws Exception {
mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false);
when(mPrefService.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD)).thenReturn(true);
mFakeClock.set(DEFAULT_TIME);
mActionManager.createAndStoreAction(CONTENT_ID_STRING, ACTION_PAYLOAD);
verify(mUploadableActionMutation)
.upsert(mUploadableActionCaptor.capture(), mContentIdStringCaptor.capture());
StreamUploadableAction action = mUploadableActionCaptor.getValue();
mActionManager.createAndUploadAction(
CONTENT_ID_STRING, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC);
verify(mFeedSessionManager).triggerUploadActions(mActionCaptor.capture());
StreamUploadableAction action =
(StreamUploadableAction) mActionCaptor.getValue().toArray()[0];
assertThat(action.getFeatureContentId()).isEqualTo(CONTENT_ID_STRING);
assertThat(action.getTimestampSeconds()).isEqualTo(DEFAULT_TIME_SECONDS);
assertThat(action.getPayload()).isEqualTo(ACTION_PAYLOAD);
}
@Test
public void triggerCreateAndUploadAction_whenLogEnabled_byNoNoticeCard() throws Exception {
mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false);
when(mPrefService.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD)).thenReturn(false);
mFakeClock.set(DEFAULT_TIME);
mActionManager.createAndUploadAction(
CONTENT_ID_STRING, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC);
verify(mFeedSessionManager).triggerUploadActions(mActionCaptor.capture());
StreamUploadableAction action =
(StreamUploadableAction) mActionCaptor.getValue().toArray()[0];
assertThat(action.getFeatureContentId()).isEqualTo(CONTENT_ID_STRING);
assertThat(action.getTimestampSeconds()).isEqualTo(DEFAULT_TIME_SECONDS);
assertThat(action.getPayload()).isEqualTo(ACTION_PAYLOAD);
assertThat(mContentIdStringCaptor.getValue()).isEqualTo(CONTENT_ID_STRING);
}
@Test
......
......@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.feed.library.feedrequestmanager;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
......@@ -59,6 +60,7 @@ import org.chromium.chrome.browser.feed.library.testing.host.stream.FakeTooltipS
import org.chromium.chrome.browser.feed.library.testing.network.FakeNetworkClient;
import org.chromium.chrome.browser.feed.library.testing.protocoladapter.FakeProtocolAdapter;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.signin.IdentityServicesProvider;
import org.chromium.chrome.browser.signin.IdentityServicesProviderJni;
......@@ -77,6 +79,7 @@ import org.chromium.components.feed.core.proto.wire.FeedActionQueryDataProto.Fee
import org.chromium.components.feed.core.proto.wire.FeedActionQueryDataProto.FeedActionQueryDataItem;
import org.chromium.components.feed.core.proto.wire.FeedQueryProto.FeedQuery;
import org.chromium.components.feed.core.proto.wire.FeedRequestProto.FeedRequest;
import org.chromium.components.feed.core.proto.wire.FeedResponseProto.FeedResponse;
import org.chromium.components.feed.core.proto.wire.RequestProto.Request;
import org.chromium.components.feed.core.proto.wire.RequestProto.Request.RequestVersion;
import org.chromium.components.feed.core.proto.wire.ResponseProto.Response;
......@@ -84,7 +87,10 @@ import org.chromium.components.feed.core.proto.wire.SemanticPropertiesProto.Sema
import org.chromium.components.feed.core.proto.wire.VersionProto.Version;
import org.chromium.components.feed.core.proto.wire.VersionProto.Version.Architecture;
import org.chromium.components.feed.core.proto.wire.VersionProto.Version.BuildType;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.signin.identitymanager.IdentityManager;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.components.user_prefs.UserPrefsJni;
import org.chromium.testing.local.LocalRobolectricTestRunner;
import java.io.IOException;
......@@ -118,6 +124,9 @@ public class FeedRequestManagerImplTest {
private final TimingUtils mTimingUtils = new TimingUtils();
private final Configuration mConfiguration = new Configuration.Builder().build();
@Rule
public JniMocker mocker = new JniMocker();
@Mock
private SchedulerApi mScheduler;
@Mock
......@@ -128,6 +137,12 @@ public class FeedRequestManagerImplTest {
private Profile mProfileMock;
@Mock
private IdentityManager mIdentifiyManagerMock;
@Mock
private UserPrefs.Natives mUserPrefsJniMock;
@Mock
private Profile mProfile;
@Mock
private PrefService mPrefService;
private Context mContext;
private ExtensionRegistryLite mRegistry;
......@@ -187,6 +202,9 @@ public class FeedRequestManagerImplTest {
when(mIdentityServicesProviderJniMock.getIdentityManager(mProfileMock))
.thenReturn(mIdentifiyManagerMock);
jniMocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock);
when(mUserPrefsJniMock.get(mProfileMock)).thenReturn(mPrefService);
mRequestManager = new FeedRequestManagerImpl(mConfiguration, mFakeNetworkClient,
mFakeProtocolAdapter, feedExtensionRegistry, mScheduler, mFakeTaskQueue,
mTimingUtils, mFakeThreadUtils, mFakeActionReader, mContext, mApplicationInfo,
......@@ -223,6 +241,62 @@ public class FeedRequestManagerImplTest {
assertThat(request).isEqualTo(expectedRequest);
}
@Test
public void testTriggerRefresh_setNoticeCardPref() throws Exception {
// Skip the read of the int that determines the length of the encoded proto. This is to
// avoid having to encode the length which is a feature we don't want to test here.
Configuration configuration =
new Configuration.Builder()
.put(ConfigKey.FEED_SERVER_RESPONSE_LENGTH_PREFIXED, false)
.build();
mRequestManager = new FeedRequestManagerImpl(configuration, mFakeNetworkClient,
mFakeProtocolAdapter, new FeedExtensionRegistry(ArrayList::new), mScheduler,
mFakeTaskQueue, mTimingUtils, mFakeThreadUtils, mFakeActionReader, mContext,
mApplicationInfo, mFakeMainThreadRunner, mFakeBasicLoggingApi,
mFakeTooltipSupportedApi);
Response response =
Response.newBuilder()
.setExtension(FeedResponse.feedResponse,
FeedResponse.newBuilder()
.addServerCapabilities(
Capability.REPORT_FEED_USER_ACTIONS_NOTICE_CARD)
.build())
.build();
mFakeNetworkClient.addResponse(new HttpResponse(200, response.toByteArray()));
mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {});
verify(mPrefService, times(1)).setBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD, true);
}
@Test
public void testLoadMore_setNoticeCardPref() throws Exception {
// Skip the read of the int that determines the length of the encoded proto. This is to
// avoid having to encode the length which is a feature we don't want to test here.
Configuration configuration =
new Configuration.Builder()
.put(ConfigKey.FEED_SERVER_RESPONSE_LENGTH_PREFIXED, false)
.build();
mRequestManager = new FeedRequestManagerImpl(configuration, mFakeNetworkClient,
mFakeProtocolAdapter, new FeedExtensionRegistry(ArrayList::new), mScheduler,
mFakeTaskQueue, mTimingUtils, mFakeThreadUtils, mFakeActionReader, mContext,
mApplicationInfo, mFakeMainThreadRunner, mFakeBasicLoggingApi,
mFakeTooltipSupportedApi);
mFakeNetworkClient.addResponse(
new HttpResponse(200, Response.getDefaultInstance().toByteArray()));
StreamToken token =
StreamToken.newBuilder()
.setNextPageToken(ByteString.copyFrom("abc", Charset.defaultCharset()))
.build();
mFakeThreadUtils.enforceMainThread(false);
mRequestManager.loadMore(token, ConsistencyToken.getDefaultInstance(), input -> {});
verify(mPrefService, never()).setBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD, true);
}
@Test
public void testTriggerRefresh_FeedUiCapabilityAddedWhenFlagIsOn() throws Exception {
testCapabilityAdded(ConfigKey.FEED_UI_ENABLED, Capability.FEED_UI);
......
......@@ -4,13 +4,20 @@
package org.chromium.chrome.browser.feed.v1;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
import androidx.annotation.Nullable;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
......@@ -21,13 +28,21 @@ import org.chromium.base.metrics.test.ShadowRecordHistogram;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.feed.library.api.host.logging.ContentLoggingData;
import org.chromium.chrome.browser.feed.library.api.host.logging.ScrollType;
import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.components.user_prefs.UserPrefsJni;
/** Tests of the {@link FeedLoggingBridge} class. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE, shadows = {ShadowRecordHistogram.class})
@Features.DisableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD)
public class FeedLoggingBridgeTest {
private static final String HISTOGRAM_ENGAGEMENT_TYPE =
"ContentSuggestions.Feed.EngagementType";
......@@ -38,17 +53,34 @@ public class FeedLoggingBridgeTest {
private FeedLoggingBridge mFeedLoggingBridge;
private FakeClock mFakeClock;
@Rule
public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor();
@Rule
public JniMocker mocker = new JniMocker();
@Mock
private FeedLoggingBridge.Natives mFeedLoggingBridgeJniMock;
@Mock
private UserPrefs.Natives mUserPrefsJniMock;
@Mock
private Profile mProfile;
@Mock
private PrefService mPrefService;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
ShadowRecordHistogram.reset();
mocker.mock(FeedLoggingBridgeJni.TEST_HOOKS, mFeedLoggingBridgeJniMock);
mocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock);
Profile.setLastUsedProfileForTesting(mProfile);
when(mUserPrefsJniMock.get(mProfile)).thenReturn(mPrefService);
Profile profile = null;
mFakeClock = new FakeClock();
mFeedLoggingBridge = new FeedLoggingBridge(profile, mFakeClock);
......@@ -161,9 +193,85 @@ public class FeedLoggingBridgeTest {
verifyHistogram(FeedLoggingBridge.FeedEngagementType.FEED_SCROLLED, 2);
}
@Test
@SmallTest
@Feature({"Feed"})
@Features.EnableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD)
public void onContentViewed_setPrefOnces_whenReachLoggingThresholdAndFeatureEnabled()
throws Exception {
ContentLoggingData data = makeContentData(2);
mFeedLoggingBridge.onContentViewed(data);
mFeedLoggingBridge.onContentViewed(data);
verify(mPrefService, times(1))
.setBoolean(Pref.HAS_REACHED_CLICK_AND_VIEW_ACTIONS_UPLOAD_CONDITIONS, true);
}
@Test
@SmallTest
@Feature({"Feed"})
@Features.DisableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD)
public void onContentViewed_dontSetPref_whenReachLoggingThresholdAndFeatureDisabled()
throws Exception {
ContentLoggingData data = makeContentData(2);
mFeedLoggingBridge.onContentViewed(data);
verify(mPrefService, never())
.setBoolean(Pref.HAS_REACHED_CLICK_AND_VIEW_ACTIONS_UPLOAD_CONDITIONS, true);
}
private void verifyHistogram(int sample, int expectedCount) {
assertEquals(expectedCount,
RecordHistogram.getHistogramValueCountForTesting(
HISTOGRAM_ENGAGEMENT_TYPE, sample));
}
private ContentLoggingData makeContentData(int positionInStream) {
return new ContentLoggingData() {
@Override
public int getPositionInStream() {
return positionInStream;
}
@Override
public long getPublishedTimeSeconds() {
return 0;
}
@Override
public long getTimeContentBecameAvailable() {
return 0;
}
@Override
public float getScore() {
return 0.0f;
}
@Override
public String getRepresentationUri() {
return "";
}
@Override
public boolean isAvailableOffline() {
return true;
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(@Nullable Object o) {
return true;
}
@Override
public String toString() {
return "";
}
};
}
}
......@@ -97,6 +97,7 @@ const base::Feature* kFeaturesExposedToJava[] = {
&features::kWebAuth,
&features::kWebNfc,
&feature_engagement::kIPHHomepagePromoCardFeature,
&feed::kInterestFeedV1ClicksAndViewsConditionalUpload,
&feed::kInterestFeedContentSuggestions,
&feed::kInterestFeedFeedback,
&feed::kInterestFeedV2,
......
......@@ -306,6 +306,8 @@ public abstract class ChromeFeatureList {
public static final String INLINE_UPDATE_FLOW = "InlineUpdateFlow";
public static final String INSTALLABLE_AMBIENT_BADGE_INFOBAR = "InstallableAmbientBadgeInfoBar";
public static final String INSTANT_START = "InstantStart";
public static final String INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD =
"InterestFeedV1ClickAndViewActionsConditionalUpload";
public static final String INTEREST_FEED_CONTENT_SUGGESTIONS = "InterestFeedContentSuggestions";
public static final String INTEREST_FEED_FEEDBACK = "InterestFeedFeedback";
public static final String INTEREST_FEED_V2 = "InterestFeedV2";
......
......@@ -31,6 +31,7 @@ java_cpp_strings("java_pref_names_srcjar") {
"//components/autofill/core/common/autofill_prefs.cc",
"//components/dom_distiller/core/pref_names.cc",
"//components/embedder_support/pref_names.cc",
"//components/feed/core/common/pref_names.cc",
"//components/feed/core/shared_prefs/pref_names.cc",
"//components/offline_pages/core/prefetch/prefetch_prefs.cc",
"//components/password_manager/core/common/password_manager_pref_names.cc",
......
......@@ -33,6 +33,10 @@ const char kUserClassifierLastTimeToUseSuggestions[] =
const char kHostOverrideHost[] = "feed.host_override.host";
const char kHostOverrideBlessNonce[] = "feed.host_override.bless_nonce";
const char kHasReachedClickAndViewActionsUploadConditions[] =
"feed.clicks_and_views_upload_conditions_reached";
const char kLastFetchHadNoticeCard[] = "feed.last_fetch_had_notice_card";
const char kThrottlerRequestCountListPrefName[] =
"feedv2.request_throttler.request_counts";
const char kThrottlerLastRequestTime[] =
......@@ -61,6 +65,9 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(feed::prefs::kMetricsData);
registry->RegisterStringPref(feed::prefs::kClientInstanceId, "");
registry->RegisterStringPref(feed::prefs::kActionsEndpointOverride, "");
registry->RegisterBooleanPref(
feed::prefs::kHasReachedClickAndViewActionsUploadConditions, false);
registry->RegisterBooleanPref(feed::prefs::kLastFetchHadNoticeCard, true);
UserClassifier::RegisterProfilePrefs(registry);
}
......
......@@ -42,6 +42,20 @@ extern const char kHostOverrideHost[];
// The pref name for the feed host override auth token.
extern const char kHostOverrideBlessNonce[];
// The pref name for the bit that determines whether the conditions are reached
// to enable the upload of click and view actions in the feed with the notice
// card when using the feature kInterestFeedConditionalClickAndViewActionUpload.
// This is for when the privacy notice card is at the second position in the
// feed. Currently only used in V1.
extern const char kHasReachedClickAndViewActionsUploadConditions[];
// The pref name for the bit that determines whether the notice card was present
// in the feed in the last fetch of content. The notice card is considered as
// present by default to make sure that the upload of click and view actions
// doesn't take place when the notice card is present but has not yet been
// detected. Currently only used in V1.
extern const char kLastFetchHadNoticeCard[];
// The following prefs are used only by v2.
// The pref name for the request throttler counts.
......
......@@ -36,6 +36,14 @@ const base::Feature kInterestFeedFeedback{"InterestFeedFeedback",
const base::Feature kReportFeedUserActions{"ReportFeedUserActions",
base::FEATURE_DISABLED_BY_DEFAULT};
// Determines whether conditions should be reached before enabling the upload of
// click and view actions in the feed (e.g., the user needs to view X cards).
// For example, This is needed when the notice card is at the second position in
// the feed.
const base::Feature kInterestFeedV1ClicksAndViewsConditionalUpload{
"InterestFeedV1ClickAndViewActionsConditionalUpload",
base::FEATURE_DISABLED_BY_DEFAULT};
const char kDefaultReferrerUrl[] =
"https://www.googleapis.com/auth/chrome-content-suggestions";
......
......@@ -30,6 +30,8 @@ extern const base::Feature kInterestFeedFeedback;
// for personalization. Also enables the feed header menu to manage the feed.
extern const base::Feature kReportFeedUserActions;
extern const base::Feature kInterestFeedV1ClicksAndViewsConditionalUpload;
std::string GetFeedReferrerUrl();
} // namespace feed
......
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