Commit c6271fc6 authored by Ian Wells's avatar Ian Wells Committed by Commit Bot

Add snackbar to FeedStreamSurface

Bug: 1044139
Change-Id: Ib06335cd3ac0f85a0c44a21094457b65585fca64
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2220228
Commit-Queue: Ian Wells <iwells@chromium.org>
Reviewed-by: default avatarJustin DeWitt <dewittj@chromium.org>
Reviewed-by: default avatarDan H <harringtond@chromium.org>
Cr-Commit-Position: refs/heads/master@{#774437}
parent 7136fdaf
......@@ -349,7 +349,8 @@ public class FeedSurfaceCoordinator implements FeedSurfaceProvider {
if (FeedServiceBridge.isEnabled()) {
// TODO(jianli): Temporary: simulate opening the feed V2 surface. This should probably
// move to FeedSurfaceMediator.
mFeedStreamSurface = new FeedStreamSurface(tabModelSelector, tabProvider, mActivity);
mFeedStreamSurface = new FeedStreamSurface(
tabModelSelector, tabProvider, mActivity, mSnackbarManager);
mFeedStreamSurface.surfaceOpened();
}
......@@ -436,7 +437,8 @@ public class FeedSurfaceCoordinator implements FeedSurfaceProvider {
new BasicStreamConfiguration(),
new BasicCardConfiguration(mActivity.getResources(), mUiConfig),
new BasicSnackbarApi(mSnackbarManager),
FeedProcessScopeFactory.getFeedOfflineIndicator(), tooltipApi)
FeedProcessScopeFactory.getFeedOfflineIndicator(), tooltipApi,
mSnackbarManager)
.setIsBackgroundDark(mShowDarkBackground)
.setIsPlaceholderShown(mIsPlaceholderShown)
.build();
......
......@@ -18,6 +18,7 @@ import org.chromium.chrome.browser.feed.library.api.host.stream.StreamConfigurat
import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipApi;
import org.chromium.chrome.browser.feed.library.common.concurrent.TaskQueue;
import org.chromium.chrome.browser.feed.library.common.logging.Dumpable;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
/** Allows interaction with the Feed library at the process leve. */
public interface ProcessScope extends Dumpable {
......@@ -37,7 +38,8 @@ public interface ProcessScope extends Dumpable {
StreamScopeBuilder createStreamScopeBuilder(Context context, ImageLoaderApi imageLoaderApi,
ActionApi actionApi, StreamConfiguration streamConfiguration,
CardConfiguration cardConfiguration, SnackbarApi snackbarApi,
OfflineIndicatorApi offlineIndicatorApi, TooltipApi tooltipApi);
OfflineIndicatorApi offlineIndicatorApi, TooltipApi tooltipApi,
SnackbarManager snackbarManager);
/** Called to destroy the scope object. */
void onDestroy();
......
......@@ -43,6 +43,7 @@ import org.chromium.chrome.browser.feed.library.piet.host.ThrowingCustomElementP
import org.chromium.chrome.browser.feed.shared.stream.Stream;
import org.chromium.chrome.browser.feed.v2.FeedStream;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
/** A builder that creates a {@link StreamScope}. */
public final class StreamScopeBuilder {
......@@ -72,6 +73,7 @@ public final class StreamScopeBuilder {
private final FeedExtensionRegistry mFeedExtensionRegistry;
private boolean mIsBackgroundDark;
private boolean mIsPlaceholderShown;
private final SnackbarManager mSnackbarManager;
// Optional internal components to override the default implementations.
private ActionParserFactory mActionParserFactory;
......@@ -91,7 +93,7 @@ public final class StreamScopeBuilder {
BasicLoggingApi basicLoggingApi, OfflineIndicatorApi offlineIndicatorApi,
FeedKnownContent feedKnownContent, TooltipApi tooltipApi,
TooltipSupportedApi tooltipSupportedApi, ApplicationInfo applicationInfo,
FeedExtensionRegistry feedExtensionRegistry) {
FeedExtensionRegistry feedExtensionRegistry, SnackbarManager snackbarManager) {
this.mContext = context;
this.mActionApi = actionApi;
this.mImageLoaderApi = imageLoaderApi;
......@@ -114,6 +116,7 @@ public final class StreamScopeBuilder {
this.mTooltipApi = tooltipApi;
this.mApplicationInfo = applicationInfo;
this.mFeedExtensionRegistry = feedExtensionRegistry;
this.mSnackbarManager = snackbarManager;
}
public StreamScopeBuilder setIsBackgroundDark(boolean isBackgroundDark) {
......@@ -163,7 +166,7 @@ public final class StreamScopeBuilder {
}
if (FeatureList.isInitialized()
&& ChromeFeatureList.isEnabled(ChromeFeatureList.INTEREST_FEED_V2)) {
mStream = new FeedStream(mContext, mIsBackgroundDark);
mStream = new FeedStream(mContext, mIsBackgroundDark, mSnackbarManager);
} else {
if (mStreamFactory == null) {
mStreamFactory = new BasicStreamFactory();
......
......@@ -38,6 +38,7 @@ import org.chromium.chrome.browser.feed.library.common.logging.Logger;
import org.chromium.chrome.browser.feed.library.common.protoextensions.FeedExtensionRegistry;
import org.chromium.chrome.browser.feed.library.common.time.Clock;
import org.chromium.chrome.browser.feed.library.common.time.TimingUtils;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
/**
* Per-process instance of the feed library.
......@@ -177,13 +178,13 @@ public final class FeedProcessScope implements ProcessScope {
public StreamScopeBuilder createStreamScopeBuilder(Context context,
ImageLoaderApi imageLoaderApi, ActionApi actionApi,
StreamConfiguration streamConfiguration, CardConfiguration cardConfiguration,
SnackbarApi snackbarApi, OfflineIndicatorApi offlineIndicatorApi,
TooltipApi tooltipApi) {
SnackbarApi snackbarApi, OfflineIndicatorApi offlineIndicatorApi, TooltipApi tooltipApi,
SnackbarManager snackbarManager) {
return new StreamScopeBuilder(context, actionApi, imageLoaderApi, mProtocolAdapter,
mFeedSessionManager, mThreadUtils, mTimingUtils, mTaskQueue, mMainThreadRunner,
mClock, mDebugBehavior, streamConfiguration, cardConfiguration, mActionManager,
mConfiguration, snackbarApi, mBasicLoggingApi, offlineIndicatorApi,
mFeedKnownContent, tooltipApi, mTooltipSupportedApi, mApplicationInfo,
mFeedExtensionRegistry);
mFeedExtensionRegistry, snackbarManager);
}
}
......@@ -16,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView;
import org.chromium.base.ObserverList;
import org.chromium.chrome.browser.feed.shared.stream.Header;
import org.chromium.chrome.browser.feed.shared.stream.Stream;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.chrome.feed.R;
import java.util.ArrayList;
......@@ -36,8 +37,8 @@ public class FeedStream implements Stream {
// TODO(jianli): To be used.
private boolean mIsStreamContentVisible = true;
public FeedStream(Context context, boolean isBackgroundDark) {
this.mFeedStreamSurface = new FeedStreamSurface(null, () -> null, context);
public FeedStream(Context context, boolean isBackgroundDark, SnackbarManager snackbarManager) {
this.mFeedStreamSurface = new FeedStreamSurface(null, () -> null, context, snackbarManager);
this.mContext =
new ContextThemeWrapper(context, (isBackgroundDark ? R.style.Dark : R.style.Light));
this.mScrollListeners = new ObserverList<ScrollListener>();
......
......@@ -21,6 +21,8 @@ import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.chrome.browser.xsurface.FeedActionsHandler;
import org.chromium.chrome.browser.xsurface.HybridListRenderer;
import org.chromium.chrome.browser.xsurface.ProcessScope;
......@@ -54,6 +56,7 @@ public class FeedStreamSurface implements SurfaceActionsHandler, FeedActionsHand
private final SurfaceScope mSurfaceScope;
private final View mRootView;
private final HybridListRenderer mHybridListRenderer;
private final SnackbarManager mSnackbarManager;
private int mHeaderCount;
......@@ -112,11 +115,12 @@ public class FeedStreamSurface implements SurfaceActionsHandler, FeedActionsHand
* Creates a {@link FeedStreamSurface} for creating native side bridge to access native feed
* client implementation.
*/
public FeedStreamSurface(
TabModelSelector tabModelSelector, Supplier<Tab> tabProvider, Context activityContext) {
public FeedStreamSurface(TabModelSelector tabModelSelector, Supplier<Tab> tabProvider,
Context activityContext, SnackbarManager snackbarManager) {
mNativeFeedStreamSurface = FeedStreamSurfaceJni.get().init(FeedStreamSurface.this);
mTabModelSelector = tabModelSelector;
mTabProvider = tabProvider;
mSnackbarManager = snackbarManager;
mContentManager = new FeedListContentManager(this, this);
......@@ -330,6 +334,25 @@ public class FeedStreamSurface implements SurfaceActionsHandler, FeedActionsHand
mNativeFeedStreamSurface, FeedStreamSurface.this, changeId);
}
@Override
public void showSnackbar(String text, String actionLabel, int durationMs,
FeedActionsHandler.SnackbarController controller) {
mSnackbarManager.showSnackbar(
Snackbar.make(text,
new SnackbarManager.SnackbarController() {
@Override
public void onAction(Object actionData) {
controller.onAction();
}
@Override
public void onDismissNoAction(Object actionData) {
controller.onDismissNoAction();
}
},
Snackbar.TYPE_ACTION, Snackbar.UMA_FEED_NTP_STREAM)
.setDuration(durationMs));
}
/**
* Informs that the surface is opened. We can request the initial set of content now. Once
* the content is available, onStreamUpdated will be called.
......
......@@ -51,6 +51,7 @@ import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock;
import org.chromium.chrome.browser.feed.library.piet.host.CustomElementProvider;
import org.chromium.chrome.browser.feed.library.piet.host.HostBindingProvider;
import org.chromium.chrome.browser.feed.shared.stream.Stream;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.testing.local.LocalRobolectricTestRunner;
/** Tests for {@link StreamScopeBuilder}. */
......@@ -104,6 +105,8 @@ public class StreamScopeBuilderTest {
private TooltipApi mTooltipApi;
@Mock
private FeedExtensionRegistry mFeedExtensionRegistry;
@Mock
private SnackbarManager mSnackbarManager;
private Context mContext;
private MainThreadRunner mMainThreadRunner;
......@@ -136,7 +139,7 @@ public class StreamScopeBuilderTest {
mMainThreadRunner, mClock, DEBUG_BEHAVIOR, mStreamConfiguration, mCardConfiguration,
mActionManager, mConfig, mSnackbarApi, mBasicLoggingApi, mOfflineIndicatorApi,
mFeedKnownContent, mTooltipApi, mTooltipSupportedApi, mApplicationInfo,
mFeedExtensionRegistry)
mFeedExtensionRegistry, mSnackbarManager)
.build();
assertThat(streamScope.getStream()).isNotNull();
assertThat(streamScope.getModelProviderFactory()).isNotNull();
......@@ -149,7 +152,7 @@ public class StreamScopeBuilderTest {
mMainThreadRunner, mClock, DEBUG_BEHAVIOR, mStreamConfiguration, mCardConfiguration,
mActionManager, mConfig, mSnackbarApi, mBasicLoggingApi, mOfflineIndicatorApi,
mFeedKnownContent, mTooltipApi, mTooltipSupportedApi, mApplicationInfo,
mFeedExtensionRegistry)
mFeedExtensionRegistry, mSnackbarManager)
.setModelProviderFactory(mModelProviderFactory)
.setCustomElementProvider(mCustomElementProvider)
.setHostBindingProvider(new HostBindingProvider())
......@@ -167,7 +170,7 @@ public class StreamScopeBuilderTest {
mMainThreadRunner, mClock, DEBUG_BEHAVIOR, mStreamConfiguration, mCardConfiguration,
mActionManager, mConfig, mSnackbarApi, mBasicLoggingApi, mOfflineIndicatorApi,
mFeedKnownContent, mTooltipApi, mTooltipSupportedApi, mApplicationInfo,
mFeedExtensionRegistry)
mFeedExtensionRegistry, mSnackbarManager)
.setStreamFactory(mStreamFactory)
.setCustomElementProvider(mCustomElementProvider)
.setHostBindingProvider(mHostBindingProvider)
......
......@@ -5,6 +5,8 @@
package org.chromium.chrome.browser.feed.v2;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.verify;
import android.app.Activity;
import android.content.Context;
......@@ -24,6 +26,8 @@ import org.robolectric.annotation.Config;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.chrome.browser.xsurface.FeedActionsHandler;
import org.chromium.components.feed.proto.FeedUiProto.Slice;
import org.chromium.components.feed.proto.FeedUiProto.StreamUpdate;
import org.chromium.components.feed.proto.FeedUiProto.StreamUpdate.SliceUpdate;
......@@ -39,6 +43,11 @@ public class FeedStreamSurfaceTest {
private FeedStreamSurface mFeedStreamSurface;
private Context mContext;
@Mock
private SnackbarManager mSnackbarManager;
@Mock
private FeedActionsHandler.SnackbarController mSnackbarController;
@Rule
public JniMocker mocker = new JniMocker();
......@@ -50,7 +59,7 @@ public class FeedStreamSurfaceTest {
MockitoAnnotations.initMocks(this);
mContext = Robolectric.buildActivity(Activity.class).get();
mocker.mock(FeedStreamSurfaceJni.TEST_HOOKS, mFeedStreamSurfaceJniMock);
mFeedStreamSurface = new FeedStreamSurface(null, () -> null, mContext);
mFeedStreamSurface = new FeedStreamSurface(null, () -> null, mContext, mSnackbarManager);
}
@Test
......@@ -320,6 +329,13 @@ public class FeedStreamSurfaceTest {
assertEquals(headers + 6, contentManager.findContentPositionByKey("i"));
}
@Test
@SmallTest
public void testShowSnackbar() {
mFeedStreamSurface.showSnackbar("message", "Undo", 50, mSnackbarController);
verify(mSnackbarManager).showSnackbar(any());
}
private SliceUpdate createSliceUpdateForExistingSlice(String sliceId) {
return SliceUpdate.newBuilder().setSliceId(sliceId).build();
}
......
......@@ -39,4 +39,29 @@ public interface FeedActionsHandler {
* Discards a previous requested dismissal denoted by change ID.
*/
default void discardDismissal(int changeId) {}
/**
* Interface for handling snackbar exit conditions.
*/
public interface SnackbarController {
/**
* Called when the snackbar's action button is tapped.
*/
default void onAction() {}
/**
* Called when the snackbar is dismissed without the button being tapped (usually when it
* times out).
*/
default void onDismissNoAction() {}
}
/**
* Show a snackbar.
* @param text Text to display.
* @param actionLabel Text for the button (e.g. "Undo").
* @param durationMs Timeout in milliseconds after which the snackbar is removed.
* @param controller Handlers for snackbar actions.
*/
default void showSnackbar(
String text, String actionLabel, int durationMs, SnackbarController controller) {}
}
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