Change StreamActionApi to only use notInterestedIn(), refactor to build the streamUplaodableAction in actionManager on the backgroundThread, and deprecate NOT_INTERESTED_IN_SOURCE/TOPIC in the protos

PiperOrigin-RevId: 242141402
Change-Id: I895748eaddf14c9645032b9932b3ae0af7db9de3
diff --git a/src/main/java/com/google/android/libraries/feed/api/actionmanager/ActionManager.java b/src/main/java/com/google/android/libraries/feed/api/actionmanager/ActionManager.java
index eb08a95..b687990 100644
--- a/src/main/java/com/google/android/libraries/feed/api/actionmanager/ActionManager.java
+++ b/src/main/java/com/google/android/libraries/feed/api/actionmanager/ActionManager.java
@@ -16,9 +16,8 @@
 
 import com.google.android.libraries.feed.common.functional.Consumer;
 import com.google.search.now.feed.client.StreamDataProto.StreamDataOperation;
-import com.google.search.now.feed.client.StreamDataProto.StreamUploadableAction;
+import com.google.search.now.wire.feed.ActionPayloadProto.ActionPayload;
 import java.util.List;
-import java.util.Set;
 
 /** Allows Stream to notify the Feed library of actions taken */
 public interface ActionManager {
@@ -52,7 +51,7 @@
    * Issues a request to record a set of actions, with the consumer being called back with the
    * resulting {@link ConsistencyToken}.
    */
-  void uploadActions(Set<StreamUploadableAction> actions);
+  void createAndUploadAction(String contentId, ActionPayload payload);
 
   /**
    * Issues a request to record a set of action and update the url with consistency token with the
diff --git a/src/main/java/com/google/android/libraries/feed/api/actionmanager/BUILD b/src/main/java/com/google/android/libraries/feed/api/actionmanager/BUILD
index cc7141c..c355eae 100644
--- a/src/main/java/com/google/android/libraries/feed/api/actionmanager/BUILD
+++ b/src/main/java/com/google/android/libraries/feed/api/actionmanager/BUILD
@@ -10,6 +10,7 @@
         "//src/main/java/com/google/android/libraries/feed/common",
         "//src/main/java/com/google/android/libraries/feed/common/functional",
         "//src/main/proto/com/google/android/libraries/feed/api/proto:client_feed_java_proto_lite",
+        "//src/main/proto/search/now/wire/feed:feed_java_proto_lite",
         "@com_google_code_findbugs_jsr305//jar",
     ],
 )
diff --git a/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/BUILD b/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/BUILD
index 46620e6..ed9a67b 100644
--- a/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/BUILD
+++ b/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/BUILD
@@ -17,6 +17,7 @@
         "//src/main/java/com/google/android/libraries/feed/sharedstream/pendingdismiss",
         "//src/main/proto/com/google/android/libraries/feed/api/proto:client_feed_java_proto_lite",
         "//src/main/proto/search/now/ui/action:feed_action_java_proto_lite",
+        "//src/main/proto/search/now/wire/feed:feed_java_proto_lite",
         "@com_google_code_findbugs_jsr305//jar",
     ],
 )
diff --git a/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/StreamActionApiImpl.java b/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/StreamActionApiImpl.java
index 48f66d2..c95533a 100644
--- a/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/StreamActionApiImpl.java
+++ b/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/StreamActionApiImpl.java
@@ -31,15 +31,13 @@
 import com.google.android.libraries.feed.sharedstream.contextmenumanager.ContextMenuManager;
 import com.google.android.libraries.feed.sharedstream.pendingdismiss.PendingDismissCallback;
 import com.google.search.now.feed.client.StreamDataProto.StreamDataOperation;
-import com.google.search.now.feed.client.StreamDataProto.StreamUploadableAction;
 import com.google.search.now.ui.action.FeedActionProto.FeedActionMetadata.ElementType;
-import com.google.search.now.ui.action.FeedActionProto.FeedActionMetadata.Type;
 import com.google.search.now.ui.action.FeedActionProto.LabelledFeedActionData;
 import com.google.search.now.ui.action.FeedActionProto.OpenContextMenuData;
 import com.google.search.now.ui.action.FeedActionProto.UndoAction;
+import com.google.search.now.wire.feed.ActionPayloadProto.ActionPayload;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 
 /** Action handler for Stream. */
@@ -124,68 +122,36 @@
   }
 
   @Override
-  public boolean canHandleNotInterestedInTopic() {
+  public boolean canHandleNotInterestedIn() {
     return true;
   }
 
   @Override
-  public void handleNotInterestedInTopic(
-      List<StreamDataOperation> dataOperations, UndoAction undoAction) {
+  public void handleNotInterestedIn(
+      List<StreamDataOperation> dataOperations,
+      UndoAction undoAction,
+      ActionPayload payload,
+      int interestType) {
     if (!undoAction.hasConfirmationLabel()) {
       dismiss(dataOperations);
-
-      // TODO: use correct value
-      basicLoggingApi.onNotInterestedIn(0, contentLoggingData, /* wasCommitted = */ true);
+      basicLoggingApi.onNotInterestedIn(
+          interestType, contentLoggingData, /* wasCommitted = */ true);
     } else {
       dismissWithSnackbar(
           undoAction,
           new PendingDismissCallback() {
             @Override
             public void onDismissReverted() {
-              basicLoggingApi.onNotInterestedIn(0, contentLoggingData, /* wasCommitted = */ false);
+              basicLoggingApi.onNotInterestedIn(
+                  interestType, contentLoggingData, /* wasCommitted = */ false);
             }
 
             @Override
             public void onDismissCommitted() {
               dismiss(dataOperations);
-              HashSet<StreamUploadableAction> actionSet = new HashSet<>();
-              actionSet.add(
-                  StreamUploadableAction.newBuilder().setFeatureContentId(contentId).build());
-              actionManager.uploadActions(actionSet);
-              basicLoggingApi.onNotInterestedIn(0, contentLoggingData, /* wasCommitted = */ true);
-            }
-          });
-    }
-  }
-
-  @Override
-  public boolean canHandleNotInterestedInSource() {
-    return true;
-  }
-
-  @Override
-  public void handleNotInterestedInSource(
-      List<StreamDataOperation> dataOperations, UndoAction undoAction) {
-    if (!undoAction.hasConfirmationLabel()) {
-      dismiss(dataOperations);
-      basicLoggingApi.onNotInterestedIn(0, contentLoggingData, /* wasCommitted = */ true);
-    } else {
-      dismissWithSnackbar(
-          undoAction,
-          new PendingDismissCallback() {
-            @Override
-            public void onDismissReverted() {
-              basicLoggingApi.onNotInterestedIn(0, contentLoggingData, /* wasCommitted = */ false);
-            }
-
-            @Override
-            public void onDismissCommitted() {
-              dismiss(dataOperations);
-              HashSet<StreamUploadableAction> actionSet = new HashSet<>();
-              actionSet.add(
-                  StreamUploadableAction.newBuilder().setFeatureContentId(contentId).build());
-              actionManager.uploadActions(actionSet);
-              basicLoggingApi.onNotInterestedIn(0, contentLoggingData, /* wasCommitted = */ true);
+              actionManager.createAndUploadAction(contentId, payload);
+              basicLoggingApi.onNotInterestedIn(
+                  interestType, contentLoggingData, /* wasCommitted = */ true);
             }
           });
     }
@@ -193,7 +159,10 @@
 
   @Override
   public void dismiss(
-      String contentId, List<StreamDataOperation> dataOperations, UndoAction undoAction) {
+      String contentId,
+      List<StreamDataOperation> dataOperations,
+      UndoAction undoAction,
+      ActionPayload payload) {
     if (!undoAction.hasConfirmationLabel()) {
       dismissLocal(contentId, dataOperations);
       basicLoggingApi.onContentDismissed(contentLoggingData, /* wasCommitted = */ true);
@@ -209,13 +178,8 @@
             @Override
             public void onDismissCommitted() {
               dismissLocal(contentId, dataOperations);
-              HashSet<StreamUploadableAction> actionSet = new HashSet<>();
-              actionSet.add(
-                  StreamUploadableAction.newBuilder()
-                      .setFeatureContentId(contentId)
-                      .setActionType(Type.DISMISS)
-                      .build());
-              actionManager.uploadActions(actionSet);
+              dismiss(dataOperations);
+              actionManager.createAndUploadAction(contentId, payload);
               basicLoggingApi.onContentDismissed(contentLoggingData, /* wasCommitted = */ true);
             }
           });
diff --git a/src/main/java/com/google/android/libraries/feed/feedactionmanager/BUILD b/src/main/java/com/google/android/libraries/feed/feedactionmanager/BUILD
index fedf502..1e6f0f1 100644
--- a/src/main/java/com/google/android/libraries/feed/feedactionmanager/BUILD
+++ b/src/main/java/com/google/android/libraries/feed/feedactionmanager/BUILD
@@ -14,6 +14,7 @@
         "//src/main/java/com/google/android/libraries/feed/common/concurrent",
         "//src/main/java/com/google/android/libraries/feed/common/functional",
         "//src/main/proto/com/google/android/libraries/feed/api/proto:client_feed_java_proto_lite",
+        "//src/main/proto/search/now/wire/feed:feed_java_proto_lite",
         "@com_google_code_findbugs_jsr305//jar",
     ],
 )
diff --git a/src/main/java/com/google/android/libraries/feed/feedactionmanager/FeedActionManagerImpl.java b/src/main/java/com/google/android/libraries/feed/feedactionmanager/FeedActionManagerImpl.java
index 3c6bfb4..2295021 100644
--- a/src/main/java/com/google/android/libraries/feed/feedactionmanager/FeedActionManagerImpl.java
+++ b/src/main/java/com/google/android/libraries/feed/feedactionmanager/FeedActionManagerImpl.java
@@ -30,8 +30,9 @@
 import com.google.android.libraries.feed.common.functional.Consumer;
 import com.google.search.now.feed.client.StreamDataProto.StreamDataOperation;
 import com.google.search.now.feed.client.StreamDataProto.StreamUploadableAction;
+import com.google.search.now.wire.feed.ActionPayloadProto.ActionPayload;
+import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 /** Default implementation of {@link ActionManager} */
 public class FeedActionManagerImpl implements ActionManager {
@@ -80,12 +81,18 @@
   }
 
   @Override
-  public void uploadActions(Set<StreamUploadableAction> actions) {
+  public void createAndUploadAction(String contentId, ActionPayload payload) {
     taskQueue.execute(
         "feedActionUpload",
         TaskType.BACKGROUND,
         () -> {
-          sessionManager.triggerUploadActions(actions);
+          HashSet<StreamUploadableAction> actionSet = new HashSet<>();
+          actionSet.add(
+              StreamUploadableAction.newBuilder()
+                  .setFeatureContentId(contentId)
+                  .setPayload(payload)
+                  .build());
+          sessionManager.triggerUploadActions(actionSet);
         });
   }
 
diff --git a/src/main/java/com/google/android/libraries/feed/feedactionparser/FeedActionParser.java b/src/main/java/com/google/android/libraries/feed/feedactionparser/FeedActionParser.java
index 20ce7a9..e7bbea9 100644
--- a/src/main/java/com/google/android/libraries/feed/feedactionparser/FeedActionParser.java
+++ b/src/main/java/com/google/android/libraries/feed/feedactionparser/FeedActionParser.java
@@ -138,14 +138,15 @@
         streamActionApi.dismiss(
             protocolAdapter.getStreamContentId(feedActionMetadata.getDismissData().getContentId()),
             streamDataOperationsResult.getValue(),
-            feedActionMetadata.getDismissData().getUndoAction());
+            feedActionMetadata.getDismissData().getUndoAction(),
+            feedActionMetadata.getDismissData().getPayload());
 
         break;
-      case NOT_INTERESTED_IN_SOURCE:
-        if (!streamActionApi.canHandleNotInterestedInSource()) {
+      case NOT_INTERESTED_IN:
+        if (!streamActionApi.canHandleNotInterestedIn()) {
           Logger.e(
               TAG,
-              "Cannot preform action not interested in topic action: StreamActionApi does not"
+              "Cannot preform action not interested in action: StreamActionApi does not"
                   + " support it.");
           return;
         }
@@ -157,40 +158,18 @@
         if (!streamDataOperationResult.isSuccessful()) {
           Logger.e(
               TAG,
-              "Cannot preform action not interested in topic action: conversion to"
+              "Cannot preform action not interested in action: conversion to"
                   + " StreamDataOperation failed.");
           return;
         }
 
-        streamActionApi.handleNotInterestedInSource(
+        streamActionApi.handleNotInterestedIn(
             streamDataOperationResult.getValue(),
-            feedActionMetadata.getNotInterestedInData().getUndoAction());
+            feedActionMetadata.getNotInterestedInData().getUndoAction(),
+            feedActionMetadata.getNotInterestedInData().getPayload(),
+            feedActionMetadata.getNotInterestedInData().getInterestType().getNumber());
         break;
-      case NOT_INTERESTED_IN_TOPIC:
-        if (!streamActionApi.canHandleNotInterestedInTopic()) {
-          Logger.e(
-              TAG,
-              "Cannot preform action not interested in topic action: StreamActionApi does not"
-                  + " support it.");
-          return;
-        }
 
-        Result<List<StreamDataOperation>> dataOperationResult =
-            protocolAdapter.createOperations(
-                feedActionMetadata.getNotInterestedInData().getDataOperationsList());
-
-        if (!dataOperationResult.isSuccessful()) {
-          Logger.e(
-              TAG,
-              "Cannot preform action not interested in topic action: conversion to"
-                  + " StreamDataOperation failed.");
-          return;
-        }
-
-        streamActionApi.handleNotInterestedInTopic(
-            dataOperationResult.getValue(),
-            feedActionMetadata.getNotInterestedInData().getUndoAction());
-        break;
       case DOWNLOAD:
         if (!streamActionApi.canDownloadUrl()) {
           Logger.e(TAG, "Cannot download: StreamActionApi does not support it");
@@ -342,10 +321,8 @@
         return contentMetadata.get() != null && streamActionApi.canDownloadUrl();
       case LEARN_MORE:
         return streamActionApi.canLearnMore();
-      case NOT_INTERESTED_IN_SOURCE:
-        return streamActionApi.canHandleNotInterestedInSource();
-      case NOT_INTERESTED_IN_TOPIC:
-        return streamActionApi.canHandleNotInterestedInTopic();
+      case NOT_INTERESTED_IN:
+        return streamActionApi.canHandleNotInterestedIn();
       case UNKNOWN:
       default:
         // TODO : Handle the action types introduced in [INTERNAL LINK]
diff --git a/src/main/java/com/google/android/libraries/feed/feedrequestmanager/BUILD b/src/main/java/com/google/android/libraries/feed/feedrequestmanager/BUILD
index 8902c83..3f19e62 100644
--- a/src/main/java/com/google/android/libraries/feed/feedrequestmanager/BUILD
+++ b/src/main/java/com/google/android/libraries/feed/feedrequestmanager/BUILD
@@ -26,7 +26,6 @@
         "//src/main/java/com/google/android/libraries/feed/host/storage",
         "//src/main/java/com/google/android/libraries/feed/host/stream",
         "//src/main/proto/com/google/android/libraries/feed/api/proto:client_feed_java_proto_lite",
-        "//src/main/proto/search/now/ui/action:feed_action_java_proto_lite",
         "//src/main/proto/search/now/wire/feed:feed_java_proto_lite",
         "@com_google_code_findbugs_jsr305//jar",
         "@com_google_protobuf_javalite//:protobuf_java_lite",
diff --git a/src/main/java/com/google/android/libraries/feed/feedrequestmanager/UploadableActionsRequestBuilder.java b/src/main/java/com/google/android/libraries/feed/feedrequestmanager/UploadableActionsRequestBuilder.java
index a45f9b6..261dfd5 100644
--- a/src/main/java/com/google/android/libraries/feed/feedrequestmanager/UploadableActionsRequestBuilder.java
+++ b/src/main/java/com/google/android/libraries/feed/feedrequestmanager/UploadableActionsRequestBuilder.java
@@ -19,6 +19,7 @@
 import com.google.android.libraries.feed.api.protocoladapter.ProtocolAdapter;
 import com.google.android.libraries.feed.common.Result;
 import com.google.search.now.feed.client.StreamDataProto.StreamUploadableAction;
+import com.google.search.now.wire.feed.ActionPayloadProto.ActionPayload;
 import com.google.search.now.wire.feed.ActionPropertiesProto.ActionProperties;
 import com.google.search.now.wire.feed.ActionRequestProto.ActionRequest;
 import com.google.search.now.wire.feed.ConsistencyTokenProto.ConsistencyToken;
@@ -77,6 +78,8 @@
       for (StreamUploadableAction action : uploadableActions) {
         String contentId = action.getFeatureContentId();
         FeedAction.Builder feedAction = FeedAction.newBuilder();
+        ActionPayload payload = action.getPayload();
+        feedAction.setActionPayload(payload);
         ActionProperties properties = actionPropertyMap.get(contentId);
         if (properties != null) {
           feedAction.setActionProperties(properties);
diff --git a/src/main/java/com/google/android/libraries/feed/feedstore/internal/PersistentFeedStore.java b/src/main/java/com/google/android/libraries/feed/feedstore/internal/PersistentFeedStore.java
index ed536d1..38a0693 100644
--- a/src/main/java/com/google/android/libraries/feed/feedstore/internal/PersistentFeedStore.java
+++ b/src/main/java/com/google/android/libraries/feed/feedstore/internal/PersistentFeedStore.java
@@ -591,11 +591,11 @@
       String contentId = entry.getKey();
       for (StreamUploadableAction removeAction : entry.getValue().removeActions()) {
         contentMutationBuilder.delete(
-            UPLOADABLE_ACTION_PREFIX + removeAction.getActionType() + contentId);
+            UPLOADABLE_ACTION_PREFIX + contentId + removeAction.getPayload().hashCode());
       }
       for (StreamUploadableAction upsertAction : entry.getValue().upsertActions()) {
         contentMutationBuilder.upsert(
-            UPLOADABLE_ACTION_PREFIX + upsertAction.getActionType() + contentId,
+            UPLOADABLE_ACTION_PREFIX + contentId + upsertAction.getPayload().hashCode(),
             upsertAction.toByteArray());
       }
     }
diff --git a/src/main/java/com/google/android/libraries/feed/host/action/BUILD b/src/main/java/com/google/android/libraries/feed/host/action/BUILD
index 0406212..8613189 100644
--- a/src/main/java/com/google/android/libraries/feed/host/action/BUILD
+++ b/src/main/java/com/google/android/libraries/feed/host/action/BUILD
@@ -11,5 +11,6 @@
         "//src/main/java/com/google/android/libraries/feed/host/stream",
         "//src/main/proto/com/google/android/libraries/feed/api/proto:client_feed_java_proto_lite",
         "//src/main/proto/search/now/ui/action:feed_action_java_proto_lite",
+        "//src/main/proto/search/now/wire/feed:feed_java_proto_lite",
     ],
 )
diff --git a/src/main/java/com/google/android/libraries/feed/host/action/StreamActionApi.java b/src/main/java/com/google/android/libraries/feed/host/action/StreamActionApi.java
index 0d1fc9a..b25674f 100644
--- a/src/main/java/com/google/android/libraries/feed/host/action/StreamActionApi.java
+++ b/src/main/java/com/google/android/libraries/feed/host/action/StreamActionApi.java
@@ -20,6 +20,7 @@
 import com.google.search.now.feed.client.StreamDataProto.StreamDataOperation;
 import com.google.search.now.ui.action.FeedActionProto.OpenContextMenuData;
 import com.google.search.now.ui.action.FeedActionProto.UndoAction;
+import com.google.search.now.wire.feed.ActionPayloadProto.ActionPayload;
 import java.util.List;
 
 /**
@@ -38,19 +39,21 @@
   boolean canDismiss();
 
   /** Dismisses card. */
-  void dismiss(String contentId, List<StreamDataOperation> dataOperations, UndoAction undoAction);
+  void dismiss(
+      String contentId,
+      List<StreamDataOperation> dataOperations,
+      UndoAction undoAction,
+      ActionPayload payload);
 
-  /** Whether or not the not interested in topic action can be handled. */
-  boolean canHandleNotInterestedInTopic();
-
-  /** Handles the Not interested in <topic> action. */
-  void handleNotInterestedInTopic(List<StreamDataOperation> dataOperations, UndoAction undoAction);
-
-  /** Whether or not the not interested in source action can be handled. */
-  boolean canHandleNotInterestedInSource();
+  /** Whether or not the not interested in action can be handled. */
+  boolean canHandleNotInterestedIn();
 
   /** Handles the Not interested in <source> action. */
-  void handleNotInterestedInSource(List<StreamDataOperation> dataOperations, UndoAction undoAction);
+  void handleNotInterestedIn(
+      List<StreamDataOperation> dataOperations,
+      UndoAction undoAction,
+      ActionPayload payload,
+      int interestType);
 
   /** Called when a client action has been performed. */
   void onClientAction(@ActionType int actionType);
diff --git a/src/main/proto/com/google/android/libraries/feed/api/proto/BUILD b/src/main/proto/com/google/android/libraries/feed/api/proto/BUILD
index 4728803..c5a7a7f 100644
--- a/src/main/proto/com/google/android/libraries/feed/api/proto/BUILD
+++ b/src/main/proto/com/google/android/libraries/feed/api/proto/BUILD
@@ -6,7 +6,6 @@
     name = "client_feed_proto",
     srcs = glob(["*.proto"]),
     deps = [
-        "//src/main/proto/search/now/ui/action:feed_action_proto",
         "//src/main/proto/search/now/ui/stream:stream_proto",
         "//src/main/proto/search/now/wire/feed:feed_proto",
     ],
diff --git a/src/main/proto/com/google/android/libraries/feed/api/proto/stream_data.proto b/src/main/proto/com/google/android/libraries/feed/api/proto/stream_data.proto
index a186ce3..853b24e 100644
--- a/src/main/proto/com/google/android/libraries/feed/api/proto/stream_data.proto
+++ b/src/main/proto/com/google/android/libraries/feed/api/proto/stream_data.proto
@@ -18,8 +18,8 @@
 
 option optimize_for=LITE_RUNTIME;
 
-import "src/main/proto/search/now/ui/action/feed_action.proto";
 import "src/main/proto/search/now/ui/stream/stream_structure.proto";
+import "src/main/proto/search/now/wire/feed/action_payload.proto";
 import "src/main/proto/search/now/wire/feed/consistency_token.proto";
 import "src/main/proto/search/now/wire/feed/opaque_action_data.proto";
 import "src/main/proto/search/now/wire/feed/piet_shared_state_item.proto";
@@ -226,8 +226,6 @@
 }
 
 message StreamUploadableAction {
-  optional ui.action.FeedActionMetadata.Type action_type = 1;
-
   optional string feature_content_id = 2;
 
   // The number of time this action was attempted to be recorded
@@ -236,7 +234,9 @@
   // When the action was recorded
   optional int64 timestamp_seconds = 4;
 
-  reserved 5;  // deprecated fields
+  optional wire.feed.ActionPayload payload = 6;
+
+  reserved 1, 5;  // deprecated fields
 }
 
 // An extension to the BasicLoggingMetadata which is used to hide the notion of
diff --git a/src/main/proto/search/now/ui/action/feed_action.proto b/src/main/proto/search/now/ui/action/feed_action.proto
index a7a868b..a3040a9 100644
--- a/src/main/proto/search/now/ui/action/feed_action.proto
+++ b/src/main/proto/search/now/ui/action/feed_action.proto
@@ -1,4 +1,4 @@
-// Copyright 2018 The Feed Authors.
+/// Copyright 2018 The Feed Authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -63,12 +63,11 @@
     DOWNLOAD = 6;
     OPEN_URL_NEW_TAB = 7;
     LEARN_MORE = 8;
-    NOT_INTERESTED_IN_TOPIC = 9 [deprecated = true];
-    NOT_INTERESTED_IN_SOURCE = 10 [deprecated = true];
     VIEW_ELEMENT = 12;
     HIDE_ELEMENT = 13;
     SHOW_TOOLTIP = 14;
     NOT_INTERESTED_IN = 15;
+    reserved 9, 10;  // Deprecated
   }
   optional Type type = 1;
 
diff --git a/src/main/proto/search/now/wire/feed/action_payload.proto b/src/main/proto/search/now/wire/feed/action_payload.proto
index 8f453e9..56c8bfa 100644
--- a/src/main/proto/search/now/wire/feed/action_payload.proto
+++ b/src/main/proto/search/now/wire/feed/action_payload.proto
@@ -30,5 +30,5 @@
 message ActionPayload {
   // Reserved fields for renderable unit extensions
   // Please use CL numbers you own for extension numbers.
-  extensions 1 to 1;
+  extensions 1 to 2;
 }
diff --git a/src/test/java/com/google/android/libraries/feed/basicstream/internal/actions/BUILD b/src/test/java/com/google/android/libraries/feed/basicstream/internal/actions/BUILD
index 0198977..0c01b10 100644
--- a/src/test/java/com/google/android/libraries/feed/basicstream/internal/actions/BUILD
+++ b/src/test/java/com/google/android/libraries/feed/basicstream/internal/actions/BUILD
@@ -26,6 +26,7 @@
         "//src/main/proto/com/google/android/libraries/feed/api/proto:client_feed_java_proto_lite",
         "//src/main/proto/search/now/ui/action:feed_action_java_proto_lite",
         "//src/main/proto/search/now/ui/action:feed_action_payload_java_proto_lite",
+        "//src/main/proto/search/now/wire/feed:feed_java_proto_lite",
         "@com_google_protobuf_javalite//:protobuf_java_lite",
         "@maven//:com_google_guava_guava",
         "@maven//:com_google_truth_truth",
diff --git a/src/test/java/com/google/android/libraries/feed/basicstream/internal/actions/StreamActionApiImplTest.java b/src/test/java/com/google/android/libraries/feed/basicstream/internal/actions/StreamActionApiImplTest.java
index 4a5cdec..fde0d43 100644
--- a/src/test/java/com/google/android/libraries/feed/basicstream/internal/actions/StreamActionApiImplTest.java
+++ b/src/test/java/com/google/android/libraries/feed/basicstream/internal/actions/StreamActionApiImplTest.java
@@ -46,7 +46,6 @@
 import com.google.android.libraries.feed.testing.sharedstream.contextmenumanager.FakeContextMenuManager;
 import com.google.common.collect.ImmutableList;
 import com.google.search.now.feed.client.StreamDataProto.StreamDataOperation;
-import com.google.search.now.feed.client.StreamDataProto.StreamUploadableAction;
 import com.google.search.now.ui.action.FeedActionPayloadProto.FeedActionPayload;
 import com.google.search.now.ui.action.FeedActionProto.FeedAction;
 import com.google.search.now.ui.action.FeedActionProto.FeedActionMetadata;
@@ -56,10 +55,10 @@
 import com.google.search.now.ui.action.FeedActionProto.OpenContextMenuData;
 import com.google.search.now.ui.action.FeedActionProto.OpenUrlData;
 import com.google.search.now.ui.action.FeedActionProto.UndoAction;
+import com.google.search.now.wire.feed.ActionPayloadProto.ActionPayload;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
@@ -80,6 +79,8 @@
   private static final String OPEN_IN_NEW_WINDOW_LABEL = "Open in new window";
   private static final String PARAM = "param";
   private static final String NEW_URL = "ooh.shiny.com";
+  private static final int INTEREST_TYPE = 2;
+  private static final ActionPayload ACTION_PAYLOAD = ActionPayload.getDefaultInstance();
   private static final LabelledFeedActionData OPEN_IN_NEW_WINDOW =
       LabelledFeedActionData.newBuilder()
           .setLabel(OPEN_IN_NEW_WINDOW_LABEL)
@@ -184,7 +185,8 @@
     String contentId = "contentId";
     List<StreamDataOperation> streamDataOperations =
         Collections.singletonList(StreamDataOperation.getDefaultInstance());
-    streamActionApi.dismiss(contentId, streamDataOperations, UndoAction.getDefaultInstance());
+    streamActionApi.dismiss(
+        contentId, streamDataOperations, UndoAction.getDefaultInstance(), ACTION_PAYLOAD);
 
     verify(actionManager)
         .dismissLocal(ImmutableList.of(contentId), streamDataOperations, SESSION_ID);
@@ -223,32 +225,17 @@
 
   @Test
   public void testHandleNotInterestedInTopic_onCommitted() {
-    testCommittedDismissWithSnackbar(Type.NOT_INTERESTED_IN_TOPIC);
+    testCommittedDismissWithSnackbar(Type.NOT_INTERESTED_IN);
   }
 
   @Test
   public void testHandleNotInterestedInTopic_onReverted() {
-    testRevertedDismissWithSnackbar(Type.NOT_INTERESTED_IN_TOPIC);
+    testRevertedDismissWithSnackbar(Type.NOT_INTERESTED_IN);
   }
 
   @Test
   public void testHandleNotInterestedInTopic_noSnackbar() {
-    testDismissNoSnackbar(Type.NOT_INTERESTED_IN_TOPIC);
-  }
-
-  @Test
-  public void testHandleNotInterestedInSource_onCommitted() {
-    testCommittedDismissWithSnackbar(Type.NOT_INTERESTED_IN_SOURCE);
-  }
-
-  @Test
-  public void testHandleNotInterestedInSource_onReverted() {
-    testRevertedDismissWithSnackbar(Type.NOT_INTERESTED_IN_SOURCE);
-  }
-
-  @Test
-  public void testHandleNotInterestedInSource_noSnackbar() {
-    testDismissNoSnackbar(Type.NOT_INTERESTED_IN_SOURCE);
+    testDismissNoSnackbar(Type.NOT_INTERESTED_IN);
   }
 
   @Test
@@ -520,13 +507,11 @@
     switch (actionType) {
       case DISMISS:
       case DISMISS_LOCAL:
-        streamActionApi.dismiss(CONTENT_ID, streamDataOperations, undoAction);
+        streamActionApi.dismiss(CONTENT_ID, streamDataOperations, undoAction, ACTION_PAYLOAD);
         break;
-      case NOT_INTERESTED_IN_SOURCE:
-        streamActionApi.handleNotInterestedInSource(streamDataOperations, undoAction);
-        break;
-      case NOT_INTERESTED_IN_TOPIC:
-        streamActionApi.handleNotInterestedInTopic(streamDataOperations, undoAction);
+      case NOT_INTERESTED_IN:
+        streamActionApi.handleNotInterestedIn(
+            streamDataOperations, undoAction, ACTION_PAYLOAD, INTEREST_TYPE);
         break;
       default:
         break;
@@ -536,33 +521,23 @@
         .triggerPendingDismissForCluster(eq(undoAction), pendingDismissCallback.capture());
 
     pendingDismissCallback.getValue().onDismissCommitted();
-    HashSet<StreamUploadableAction> actionSet = new HashSet<>();
     switch (actionType) {
       case DISMISS:
         verify(actionManager)
             .dismissLocal(ImmutableList.of(CONTENT_ID), streamDataOperations, SESSION_ID);
         verify(basicLoggingApi).onContentDismissed(contentLoggingData, /*wasCommitted =*/ true);
-        actionSet.add(
-            StreamUploadableAction.newBuilder()
-                .setFeatureContentId(CONTENT_ID)
-                .setActionType(FeedActionMetadata.Type.DISMISS)
-                .build());
-        verify(actionManager).uploadActions(actionSet);
+        verify(actionManager).createAndUploadAction(CONTENT_ID, ACTION_PAYLOAD);
         break;
       case DISMISS_LOCAL:
         verify(actionManager)
             .dismissLocal(ImmutableList.of(CONTENT_ID), streamDataOperations, SESSION_ID);
         verify(basicLoggingApi).onContentDismissed(contentLoggingData, /*wasCommitted =*/ true);
         break;
-      case NOT_INTERESTED_IN_SOURCE:
-      case NOT_INTERESTED_IN_TOPIC:
+      case NOT_INTERESTED_IN:
         verify(actionManager).dismiss(streamDataOperations, SESSION_ID);
-        verify(basicLoggingApi).onNotInterestedIn(0, contentLoggingData, /*wasCommitted =*/ true);
-        actionSet.add(
-            StreamUploadableAction.newBuilder()
-                .setFeatureContentId(CONTENT_ID)
-                .build());
-        verify(actionManager).uploadActions(actionSet);
+        verify(basicLoggingApi)
+            .onNotInterestedIn(INTEREST_TYPE, contentLoggingData, /*wasCommitted =*/ true);
+        verify(actionManager).createAndUploadAction(CONTENT_ID, ACTION_PAYLOAD);
         break;
       default:
         break;
@@ -579,13 +554,11 @@
     switch (actionType) {
       case DISMISS:
       case DISMISS_LOCAL:
-        streamActionApi.dismiss(contentId, streamDataOperations, undoAction);
+        streamActionApi.dismiss(contentId, streamDataOperations, undoAction, ACTION_PAYLOAD);
         break;
-      case NOT_INTERESTED_IN_SOURCE:
-        streamActionApi.handleNotInterestedInSource(streamDataOperations, undoAction);
-        break;
-      case NOT_INTERESTED_IN_TOPIC:
-        streamActionApi.handleNotInterestedInTopic(streamDataOperations, undoAction);
+      case NOT_INTERESTED_IN:
+        streamActionApi.handleNotInterestedIn(
+            streamDataOperations, undoAction, ACTION_PAYLOAD, INTEREST_TYPE);
         break;
       default:
         break;
@@ -603,9 +576,9 @@
       case DISMISS_LOCAL:
         verify(basicLoggingApi).onContentDismissed(contentLoggingData, /*wasCommitted =*/ false);
         break;
-      case NOT_INTERESTED_IN_SOURCE:
-      case NOT_INTERESTED_IN_TOPIC:
-        verify(basicLoggingApi).onNotInterestedIn(0, contentLoggingData, /*wasCommitted =*/ false);
+      case NOT_INTERESTED_IN:
+        verify(basicLoggingApi)
+            .onNotInterestedIn(INTEREST_TYPE, contentLoggingData, /*wasCommitted =*/ false);
         break;
       default:
         break;
@@ -620,13 +593,11 @@
     switch (actionType) {
       case DISMISS:
       case DISMISS_LOCAL:
-        streamActionApi.dismiss(contentId, streamDataOperations, undoAction);
+        streamActionApi.dismiss(contentId, streamDataOperations, undoAction, ACTION_PAYLOAD);
         break;
-      case NOT_INTERESTED_IN_SOURCE:
-        streamActionApi.handleNotInterestedInSource(streamDataOperations, undoAction);
-        break;
-      case NOT_INTERESTED_IN_TOPIC:
-        streamActionApi.handleNotInterestedInTopic(streamDataOperations, undoAction);
+      case NOT_INTERESTED_IN:
+        streamActionApi.handleNotInterestedIn(
+            streamDataOperations, undoAction, ACTION_PAYLOAD, INTEREST_TYPE);
         break;
       default:
         break;
@@ -641,10 +612,10 @@
             .dismissLocal(ImmutableList.of(contentId), streamDataOperations, SESSION_ID);
         verify(basicLoggingApi).onContentDismissed(contentLoggingData, /*wasCommitted =*/ true);
         break;
-      case NOT_INTERESTED_IN_SOURCE:
-      case NOT_INTERESTED_IN_TOPIC:
+      case NOT_INTERESTED_IN:
         verify(actionManager).dismiss(streamDataOperations, SESSION_ID);
-        verify(basicLoggingApi).onNotInterestedIn(0, contentLoggingData, /*wasCommitted =*/ true);
+        verify(basicLoggingApi)
+            .onNotInterestedIn(INTEREST_TYPE, contentLoggingData, /*wasCommitted =*/ true);
         break;
       default:
         break;
diff --git a/src/test/java/com/google/android/libraries/feed/feedactionmanager/FeedActionManagerImplTest.java b/src/test/java/com/google/android/libraries/feed/feedactionmanager/FeedActionManagerImplTest.java
index 0d2b2db..c2ee6df 100644
--- a/src/test/java/com/google/android/libraries/feed/feedactionmanager/FeedActionManagerImplTest.java
+++ b/src/test/java/com/google/android/libraries/feed/feedactionmanager/FeedActionManagerImplTest.java
@@ -39,10 +39,11 @@
 import com.google.search.now.feed.client.StreamDataProto.StreamStructure;
 import com.google.search.now.feed.client.StreamDataProto.StreamStructure.Operation;
 import com.google.search.now.feed.client.StreamDataProto.StreamUploadableAction;
+import com.google.search.now.wire.feed.ActionPayloadProto.ActionPayload;
 import com.google.search.now.wire.feed.ConsistencyTokenProto.ConsistencyToken;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -72,6 +73,7 @@
   @Captor private ArgumentCaptor<Result<List<StreamDataOperation>>> streamDataOperationsCaptor;
   @Captor private ArgumentCaptor<MutationContext> mutationContextCaptor;
   @Captor private ArgumentCaptor<Consumer<Result<ConsistencyToken>>> consumerCaptor;
+  @Captor private ArgumentCaptor<Set<StreamUploadableAction>> actionCaptor;
 
   private ActionManager actionManager;
 
@@ -172,11 +174,13 @@
   }
 
   @Test
-  public void triggerUploadActions() throws Exception {
-    HashSet<StreamUploadableAction> actionSet = new HashSet<>();
-    actionSet.add(StreamUploadableAction.getDefaultInstance());
-    actionManager.uploadActions(actionSet);
-    verify(sessionManager).triggerUploadActions(actionSet);
+  public void triggerCreateAndUploadAction() throws Exception {
+    ActionPayload payload = ActionPayload.getDefaultInstance();
+    actionManager.createAndUploadAction(CONTENT_ID_STRING, payload);
+    verify(sessionManager).triggerUploadActions(actionCaptor.capture());
+    StreamUploadableAction action = (StreamUploadableAction) actionCaptor.getValue().toArray()[0];
+    assertThat(action.getFeatureContentId()).isEqualTo(CONTENT_ID_STRING);
+    assertThat(action.getPayload()).isEqualTo(payload);
   }
 
   @Test
diff --git a/src/test/java/com/google/android/libraries/feed/feedactionparser/FeedActionParserTest.java b/src/test/java/com/google/android/libraries/feed/feedactionparser/FeedActionParserTest.java
index 90cc95b..4915ed0 100644
--- a/src/test/java/com/google/android/libraries/feed/feedactionparser/FeedActionParserTest.java
+++ b/src/test/java/com/google/android/libraries/feed/feedactionparser/FeedActionParserTest.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.never;
@@ -57,6 +58,7 @@
 import com.google.search.now.ui.action.FeedActionProto.UndoAction;
 import com.google.search.now.ui.action.PietExtensionsProto.PietFeedActionPayload;
 import com.google.search.now.ui.piet.ActionsProto.Action;
+import com.google.search.now.wire.feed.ActionPayloadProto.ActionPayload;
 import com.google.search.now.wire.feed.ContentIdProto.ContentId;
 import com.google.search.now.wire.feed.DataOperationProto.DataOperation;
 import java.util.List;
@@ -310,32 +312,19 @@
                   .build())
           .build();
 
-  private static final FeedActionPayload NOT_INTERESTED_IN_SOURCE =
+  private static final FeedActionPayload NOT_INTERESTED_IN =
       FeedActionPayload.newBuilder()
           .setExtension(
               FeedAction.feedActionExtension,
               FeedAction.newBuilder()
                   .setMetadata(
                       FeedActionMetadata.newBuilder()
-                          .setType(Type.NOT_INTERESTED_IN_SOURCE)
+                          .setType(Type.NOT_INTERESTED_IN)
                           .setNotInterestedInData(
                               NotInterestedInData.newBuilder()
                                   .addDataOperations(DataOperation.getDefaultInstance())
-                                  .setUndoAction(UNDO_ACTION)))
-                  .build())
-          .build();
-
-  private static final FeedActionPayload NOT_INTERESTED_IN_TOPIC =
-      FeedActionPayload.newBuilder()
-          .setExtension(
-              FeedAction.feedActionExtension,
-              FeedAction.newBuilder()
-                  .setMetadata(
-                      FeedActionMetadata.newBuilder()
-                          .setType(Type.NOT_INTERESTED_IN_TOPIC)
-                          .setNotInterestedInData(
-                              NotInterestedInData.newBuilder()
-                                  .addDataOperations(DataOperation.getDefaultInstance())
+                                  .setInterestType(NotInterestedInData.RecordedInterestType.SOURCE)
+                                  .setPayload(ActionPayload.getDefaultInstance())
                                   .setUndoAction(UNDO_ACTION)))
                   .build())
           .build();
@@ -675,14 +664,18 @@
     feedActionParser.parseFeedActionPayload(
         DISMISS_LOCAL_FEED_ACTION, streamActionApi, /* view= */ null, ActionSource.CLICK);
     verify(streamActionApi, never())
-        .dismiss(anyString(), Mockito.anyListOf(StreamDataOperation.class), any());
+        .dismiss(
+            anyString(),
+            Mockito.anyListOf(StreamDataOperation.class),
+            any(UndoAction.class),
+            any(ActionPayload.class));
   }
 
   @Test
-  public void testNotInterestedInTopic_noApiSupport() {
-    when(streamActionApi.canHandleNotInterestedInTopic()).thenReturn(false);
+  public void testNotInterestedIn_noApiSupport() {
+    when(streamActionApi.canHandleNotInterestedIn()).thenReturn(false);
     when(protocolAdapter.createOperations(
-            NOT_INTERESTED_IN_TOPIC
+            NOT_INTERESTED_IN
                 .getExtension(FeedAction.feedActionExtension)
                 .getMetadata()
                 .getNotInterestedInData()
@@ -691,23 +684,11 @@
     feedActionParser.parseFeedActionPayload(
         DISMISS_LOCAL_FEED_ACTION, streamActionApi, /* view= */ null, ActionSource.CLICK);
     verify(streamActionApi, never())
-        .handleNotInterestedInTopic(Mockito.anyListOf(StreamDataOperation.class), any());
-  }
-
-  @Test
-  public void testNotInterestedInSource_noApiSupport() {
-    when(streamActionApi.canHandleNotInterestedInSource()).thenReturn(false);
-    when(protocolAdapter.createOperations(
-            NOT_INTERESTED_IN_SOURCE
-                .getExtension(FeedAction.feedActionExtension)
-                .getMetadata()
-                .getNotInterestedInData()
-                .getDataOperationsList()))
-        .thenReturn(Result.success(streamDataOperations));
-    feedActionParser.parseFeedActionPayload(
-        DISMISS_LOCAL_FEED_ACTION, streamActionApi, /* view= */ null, ActionSource.CLICK);
-    verify(streamActionApi, never())
-        .handleNotInterestedInSource(Mockito.anyListOf(StreamDataOperation.class), any());
+        .handleNotInterestedIn(
+            Mockito.anyListOf(StreamDataOperation.class),
+            any(UndoAction.class),
+            any(ActionPayload.class),
+            anyInt());
   }
 
   @Test
@@ -726,7 +707,11 @@
         /* view= */ null,
         ActionSource.CLICK);
     verify(streamActionApi, never())
-        .dismiss(anyString(), Mockito.anyListOf(StreamDataOperation.class), any());
+        .dismiss(
+            anyString(),
+            Mockito.anyListOf(StreamDataOperation.class),
+            any(UndoAction.class),
+            any(ActionPayload.class));
   }
 
   @Test
@@ -745,7 +730,11 @@
         DISMISS_LOCAL_FEED_ACTION, streamActionApi, /* view= */ null, ActionSource.CLICK);
 
     verify(streamActionApi, never())
-        .dismiss(anyString(), Mockito.anyListOf(StreamDataOperation.class), any());
+        .dismiss(
+            anyString(),
+            Mockito.anyListOf(StreamDataOperation.class),
+            any(UndoAction.class),
+            any(ActionPayload.class));
   }
 
   @Test
@@ -763,16 +752,21 @@
     feedActionParser.parseFeedActionPayload(
         DISMISS_LOCAL_FEED_ACTION, streamActionApi, /* view= */ null, ActionSource.CLICK);
 
-    verify(streamActionApi).dismiss(DISMISS_CONTENT_ID_STRING, streamDataOperations, UNDO_ACTION);
+    verify(streamActionApi)
+        .dismiss(
+            DISMISS_CONTENT_ID_STRING,
+            streamDataOperations,
+            UNDO_ACTION,
+            ActionPayload.getDefaultInstance());
   }
 
   @Test
-  public void testNotInterestedInSource() {
+  public void testNotInterestedIn() {
     when(streamActionApi.canDismiss()).thenReturn(true);
-    when(streamActionApi.canHandleNotInterestedInSource()).thenReturn(true);
+    when(streamActionApi.canHandleNotInterestedIn()).thenReturn(true);
 
     when(protocolAdapter.createOperations(
-            NOT_INTERESTED_IN_SOURCE
+            NOT_INTERESTED_IN
                 .getExtension(FeedAction.feedActionExtension)
                 .getMetadata()
                 .getNotInterestedInData()
@@ -780,28 +774,14 @@
         .thenReturn(Result.success(streamDataOperations));
 
     feedActionParser.parseFeedActionPayload(
-        NOT_INTERESTED_IN_SOURCE, streamActionApi, /* view= */ null, ActionSource.CLICK);
+        NOT_INTERESTED_IN, streamActionApi, /* view= */ null, ActionSource.CLICK);
 
-    verify(streamActionApi).handleNotInterestedInSource(streamDataOperations, UNDO_ACTION);
-  }
-
-  @Test
-  public void testNotInterestedInTopic() {
-    when(streamActionApi.canDismiss()).thenReturn(true);
-    when(streamActionApi.canHandleNotInterestedInTopic()).thenReturn(true);
-
-    when(protocolAdapter.createOperations(
-            NOT_INTERESTED_IN_TOPIC
-                .getExtension(FeedAction.feedActionExtension)
-                .getMetadata()
-                .getNotInterestedInData()
-                .getDataOperationsList()))
-        .thenReturn(Result.success(streamDataOperations));
-
-    feedActionParser.parseFeedActionPayload(
-        NOT_INTERESTED_IN_TOPIC, streamActionApi, /* view= */ null, ActionSource.CLICK);
-
-    verify(streamActionApi).handleNotInterestedInTopic(streamDataOperations, UNDO_ACTION);
+    verify(streamActionApi)
+        .handleNotInterestedIn(
+            streamDataOperations,
+            UNDO_ACTION,
+            ActionPayload.getDefaultInstance(),
+            NotInterestedInData.RecordedInterestType.SOURCE.getNumber());
   }
 
   @Test
diff --git a/src/test/java/com/google/android/libraries/feed/feedrequestmanager/BUILD b/src/test/java/com/google/android/libraries/feed/feedrequestmanager/BUILD
index 5f7a901..4891933 100644
--- a/src/test/java/com/google/android/libraries/feed/feedrequestmanager/BUILD
+++ b/src/test/java/com/google/android/libraries/feed/feedrequestmanager/BUILD
@@ -84,7 +84,6 @@
         "//src/main/java/com/google/android/libraries/feed/testing/actionmanager",
         "//src/main/java/com/google/android/libraries/feed/testing/protocoladapter",
         "//src/main/proto/com/google/android/libraries/feed/api/proto:client_feed_java_proto_lite",
-        "//src/main/proto/search/now/ui/action:feed_action_java_proto_lite",
         "//src/main/proto/search/now/wire/feed:feed_java_proto_lite",
         "//src/test/proto/search/now/wire/feed:feed_test_java_proto_lite",
         "@com_google_protobuf_javalite//:protobuf_java_lite",
diff --git a/src/test/java/com/google/android/libraries/feed/feedrequestmanager/UploadableActionsRequestBuilderTest.java b/src/test/java/com/google/android/libraries/feed/feedrequestmanager/UploadableActionsRequestBuilderTest.java
index 70b5bbf..338075c 100644
--- a/src/test/java/com/google/android/libraries/feed/feedrequestmanager/UploadableActionsRequestBuilderTest.java
+++ b/src/test/java/com/google/android/libraries/feed/feedrequestmanager/UploadableActionsRequestBuilderTest.java
@@ -21,7 +21,8 @@
 import com.google.android.libraries.feed.testing.protocoladapter.FakeProtocolAdapter;
 import com.google.protobuf.ByteString;
 import com.google.search.now.feed.client.StreamDataProto.StreamUploadableAction;
-import com.google.search.now.ui.action.FeedActionProto.FeedActionMetadata.Type;
+import com.google.search.now.wire.feed.ActionPayloadForTestProto.ActionPayloadForTest;
+import com.google.search.now.wire.feed.ActionPayloadProto.ActionPayload;
 import com.google.search.now.wire.feed.ActionPropertiesProto.ActionProperties;
 import com.google.search.now.wire.feed.ActionRequestProto.ActionRequest;
 import com.google.search.now.wire.feed.ConsistencyTokenProto.ConsistencyToken;
@@ -40,7 +41,12 @@
 @RunWith(RobolectricTestRunner.class)
 public class UploadableActionsRequestBuilderTest {
   private static final String CONTENT_ID = "contentId";
-
+  private final ActionPayload payload =
+      ActionPayload.newBuilder()
+          .setExtension(
+              ActionPayloadForTest.actionPayloadForTestExtension,
+              ActionPayloadForTest.newBuilder().setId(CONTENT_ID).build())
+          .build();
   private UploadableActionsRequestBuilder builder;
   private HashSet<StreamUploadableAction> actionSet = new HashSet<>();
   private ConsistencyToken token =
@@ -68,7 +74,7 @@
     actionSet.add(
         StreamUploadableAction.newBuilder()
             .setFeatureContentId(CONTENT_ID)
-            .setActionType(Type.DISMISS)
+            .setPayload(payload)
             .build());
     requestBuilder =
         ActionRequest.newBuilder()
@@ -78,11 +84,12 @@
 
   @Test
   public void testUploadableActionsRequest_noToken() throws Exception {
-
+ 
     FeedAction.Builder feedAction =
         FeedAction.newBuilder()
             .setActionProperties(ActionProperties.newBuilder().setActionData(data).build());
     feedAction.setContentId(ContentId.getDefaultInstance());
+    feedAction.setActionPayload(payload);
     feedActionRequestBuilder.addFeedAction(feedAction);
     requestBuilder.setExtension(
         FeedActionRequest.feedActionRequest, feedActionRequestBuilder.build());
@@ -109,6 +116,7 @@
         FeedAction.newBuilder()
             .setActionProperties(ActionProperties.newBuilder().setActionData(data).build());
     feedAction.setContentId(ContentId.getDefaultInstance());
+    feedAction.setActionPayload(payload);
     feedActionRequestBuilder.addFeedAction(feedAction);
     feedActionRequestBuilder.setConsistencyToken(token);
     requestBuilder.setExtension(
diff --git a/src/test/proto/search/now/wire/feed/BUILD b/src/test/proto/search/now/wire/feed/BUILD
index 16b9e6b..b4c470d 100644
--- a/src/test/proto/search/now/wire/feed/BUILD
+++ b/src/test/proto/search/now/wire/feed/BUILD
@@ -1,7 +1,10 @@
-package(default_visibility = [
-    "//src/main/java/com/google/android/libraries/feed/feedstore:__subpackages__",
-    "//src/test/java/com/google/android/libraries/feed:__subpackages__",
-])
+package(
+    default_testonly = 1,
+    default_visibility = [
+        "//src/main/java/com/google/android/libraries/feed/feedstore:__subpackages__",
+        "//src/test/java/com/google/android/libraries/feed:__subpackages__",
+    ],
+)
 
 licenses(["notice"])  # Apache 2
 
diff --git a/src/test/proto/search/now/wire/feed/action_payload_for_test.proto b/src/test/proto/search/now/wire/feed/action_payload_for_test.proto
new file mode 100644
index 0000000..c76fb1b
--- /dev/null
+++ b/src/test/proto/search/now/wire/feed/action_payload_for_test.proto
@@ -0,0 +1,35 @@
+// Copyright 2019 The Feed Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+
+package search.now.wire.feed;
+
+option optimize_for=LITE_RUNTIME;
+
+import "src/main/proto/search/now/wire/feed/action_payload.proto";
+
+option java_package = "com.google.search.now.wire.feed";
+option java_outer_classname = "ActionPayloadForTestProto";
+
+// A proto that extends feed_action.ActionPayload and carries data associated
+// with the not interested in action.
+message ActionPayloadForTest {
+  // The mid that represents the topic of the story on the card
+  optional string id = 1;
+
+  extend search.now.wire.feed.ActionPayload {
+    optional ActionPayloadForTest action_payload_for_test_extension = 2;
+  }
+}