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