Commit 3263cc61 authored by Jian Li's avatar Jian Li Committed by Commit Bot

Implementation of ListContentManager for feed

ListContentManagerImpl supports both native view and external view.

The methods defined in feed/v2/FeedActionHandler has been merged to
xsurface/FeedActionsHandler, except navigate* methods that are already
included in xsurface/SurfaceActionHandler.

Bug: 1044139
Change-Id: Ic708a1295e2a0e6700f5b72195940a8bd365c76a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2133110
Commit-Queue: Jian Li <jianli@chromium.org>
Reviewed-by: default avatarCathy Li <chili@chromium.org>
Reviewed-by: default avatarDan H <harringtond@chromium.org>
Cr-Commit-Position: refs/heads/master@{#756484}
parent fbff5c4f
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.feed.v2;
/**
* Interface to handle the actions user can trigger on the feed.
*/
public interface FeedActionHandler {
String KEY = "FeedActions";
/**
* Navigates the current tab to a particular URL.
*/
void navigate(String url);
/**
* Navigates a new tab to a particular URL.
*/
void navigateInNewTab(String url);
/**
* Requests additional content to be loaded. Once the load is completed, onStreamUpdated will be
* called.
*/
void loadMore();
/**
* Requests to dismiss a card. A change ID will be returned and it can be used to commit or
* discard the change.
*/
int requestDismissal();
/**
* Commits a previous requested dismissal denoted by change ID.
*/
void commitDismissal(int changeId);
/**
* Discards a previous requested dismissal denoted by change ID.
*/
void discardDismissal(int changeId);
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.feed.v2;
import android.view.View;
import android.view.ViewGroup;
import org.chromium.chrome.browser.xsurface.FeedActionsHandler;
import org.chromium.chrome.browser.xsurface.ListContentManager;
import org.chromium.chrome.browser.xsurface.ListContentManagerObserver;
import org.chromium.chrome.browser.xsurface.SurfaceActionsHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Implementation of ListContentManager that manages a list of feed contents that are supported by
* either native view or external surface controlled view.
*/
public class FeedListContentManager implements ListContentManager {
/**
* Encapsulates the content of an item stored and managed by ListContentManager.
*/
public interface FeedContent {
/**
* Returns true if the content is supported by the native view.
*/
boolean isNativeView();
}
/**
* For the content that is supported by external surface controlled view.
*/
public static class ExternalViewContent implements FeedContent {
private final byte[] mData;
public ExternalViewContent(byte[] data) {
mData = data;
}
/**
* Returns the raw bytes that are passed to the external surface for rendering if the
* content is supported by the external surface controlled view.
*/
public byte[] getBytes() {
return mData;
}
@Override
public boolean isNativeView() {
return false;
}
}
/**
* For the content that is supported by the native view.
*/
public static class NativeViewContent implements FeedContent {
private final View mNativeView;
public NativeViewContent(View nativeView) {
mNativeView = nativeView;
}
/**
* Returns the native view if the content is supported by it. Null otherwise.
*/
public View getNativeView() {
return mNativeView;
}
@Override
public boolean isNativeView() {
return true;
}
}
private ArrayList<FeedContent> mFeedContentList;
private ArrayList<ListContentManagerObserver> mObservers;
private final Map<String, Object> mHandlers;
FeedListContentManager(
SurfaceActionsHandler surfaceActionsHandler, FeedActionsHandler feedActionsHandler) {
mFeedContentList = new ArrayList<FeedContent>();
mObservers = new ArrayList<ListContentManagerObserver>();
mHandlers = new HashMap<String, Object>();
mHandlers.put(SurfaceActionsHandler.KEY, surfaceActionsHandler);
mHandlers.put(FeedActionsHandler.KEY, feedActionsHandler);
}
/**
* Adds a list of the contents, starting at the specified position.
*
* @param index The index at which to insert the first content from the specified collection.
* @param contents The collection containing contents to be added.
*/
public void addContents(int index, List<FeedContent> contents) {
assert index >= 0 && index < mFeedContentList.size();
mFeedContentList.addAll(index, contents);
for (ListContentManagerObserver observer : mObservers) {
observer.onItemRangeInserted(index, contents.size());
}
}
/**
* Removes the specified count of contents starting from the speicified position.
*
* @param index The index of the first content to be removed.
* @param count The number of contents to be removed.
*/
public void removeContents(int index, int count) {
assert index >= 0 && index < mFeedContentList.size();
assert index + count < mFeedContentList.size();
mFeedContentList.subList(index, index + count).clear();
for (ListContentManagerObserver observer : mObservers) {
observer.onItemRangeInserted(index, count);
}
}
/**
* Updates a list of the contents, starting at the specified position.
*
* @param index The index at which to update the first content from the specified collection.
* @param contents The collection containing contents to be updated.
*/
public void updateContents(int index, List<FeedContent> contents) {
assert index >= 0 && index < mFeedContentList.size();
assert index + contents.size() < mFeedContentList.size();
int pos = index;
for (FeedContent content : contents) {
mFeedContentList.set(pos++, content);
}
for (ListContentManagerObserver observer : mObservers) {
observer.onItemRangeChanged(index, contents.size());
}
}
/**
* Moves the content to a different position.
*
* @param curIndex The index of the content to be moved.
* @param newIndex The new index where the content is being moved to.
*/
public void moveContents(int curIndex, int newIndex) {
assert curIndex >= 0 && curIndex < mFeedContentList.size();
assert newIndex >= 0 && newIndex < mFeedContentList.size();
int lowIndex;
int highIndex;
int distance;
if (curIndex < newIndex) {
lowIndex = curIndex;
highIndex = newIndex;
distance = -1;
} else if (curIndex > newIndex) {
lowIndex = newIndex;
highIndex = curIndex;
distance = 1;
} else {
return;
}
Collections.rotate(mFeedContentList.subList(lowIndex, highIndex + 1), distance);
for (ListContentManagerObserver observer : mObservers) {
observer.onItemMoved(curIndex, newIndex);
}
}
@Override
public boolean isNativeView(int index) {
return index == 0 || mFeedContentList.get(index - 1).isNativeView();
}
@Override
public byte[] getExternalViewBytes(int index) {
assert !mFeedContentList.get(index - 1).isNativeView();
ExternalViewContent externalViewContent =
(ExternalViewContent) mFeedContentList.get(index - 1);
return externalViewContent.getBytes();
}
@Override
public Map<String, Object> getContextValues(int index) {
return mHandlers;
}
@Override
public View getNativeView(int index, ViewGroup parent) {
assert mFeedContentList.get(index - 1).isNativeView();
NativeViewContent nativeViewContent = (NativeViewContent) mFeedContentList.get(index - 1);
return nativeViewContent.getNativeView();
}
@Override
public void bindNativeView(int index, View v) {
// TODO(jianli): to be implemented.
}
@Override
public int getItemCount() {
return mFeedContentList.size();
}
@Override
public void addObserver(ListContentManagerObserver observer) {
mObservers.add(observer);
}
@Override
public void removeObserver(ListContentManagerObserver observer) {
mObservers.remove(observer);
}
}
...@@ -11,6 +11,8 @@ import org.chromium.chrome.browser.ChromeActivity; ...@@ -11,6 +11,8 @@ import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabLaunchType; import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.xsurface.FeedActionsHandler;
import org.chromium.chrome.browser.xsurface.SurfaceActionsHandler;
import org.chromium.components.feed.proto.FeedUiProto.StreamUpdate; import org.chromium.components.feed.proto.FeedUiProto.StreamUpdate;
import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.ui.base.PageTransition; import org.chromium.ui.base.PageTransition;
...@@ -24,7 +26,7 @@ import java.util.List; ...@@ -24,7 +26,7 @@ import java.util.List;
* Created once for each StreamSurfaceMediator corresponding to each NTP/start surface. * Created once for each StreamSurfaceMediator corresponding to each NTP/start surface.
*/ */
@JNINamespace("feed") @JNINamespace("feed")
public class FeedStreamSurface implements FeedActionHandler { public class FeedStreamSurface implements SurfaceActionsHandler, FeedActionsHandler {
private final long mNativeFeedStreamSurface; private final long mNativeFeedStreamSurface;
private final ChromeActivity mActivity; private final ChromeActivity mActivity;
...@@ -35,6 +37,11 @@ public class FeedStreamSurface implements FeedActionHandler { ...@@ -35,6 +37,11 @@ public class FeedStreamSurface implements FeedActionHandler {
public FeedStreamSurface(ChromeActivity activity) { public FeedStreamSurface(ChromeActivity activity) {
mNativeFeedStreamSurface = FeedStreamSurfaceJni.get().init(FeedStreamSurface.this); mNativeFeedStreamSurface = FeedStreamSurfaceJni.get().init(FeedStreamSurface.this);
mActivity = activity; mActivity = activity;
FeedListContentManager manager = new FeedListContentManager(this, this);
// TODO(jianli): Get HybridListRender in order to bind FeedListContentManager to it.
// Then add the returned RecyclerView to NTP layout.
} }
/** /**
...@@ -50,7 +57,7 @@ public class FeedStreamSurface implements FeedActionHandler { ...@@ -50,7 +57,7 @@ public class FeedStreamSurface implements FeedActionHandler {
} }
@Override @Override
public void navigate(String url) { public void navigateTab(String url) {
LoadUrlParams loadUrlParams = new LoadUrlParams(url); LoadUrlParams loadUrlParams = new LoadUrlParams(url);
loadUrlParams.setTransitionType(PageTransition.AUTO_BOOKMARK); loadUrlParams.setTransitionType(PageTransition.AUTO_BOOKMARK);
mActivity.getActivityTabProvider().get().loadUrl(loadUrlParams); mActivity.getActivityTabProvider().get().loadUrl(loadUrlParams);
...@@ -59,7 +66,7 @@ public class FeedStreamSurface implements FeedActionHandler { ...@@ -59,7 +66,7 @@ public class FeedStreamSurface implements FeedActionHandler {
} }
@Override @Override
public void navigateInNewTab(String url) { public void navigateNewTab(String url) {
TabModelSelector tabModelSelector = mActivity.getTabModelSelector(); TabModelSelector tabModelSelector = mActivity.getTabModelSelector();
Tab tab = mActivity.getActivityTabProvider().get(); Tab tab = mActivity.getActivityTabProvider().get();
tabModelSelector.openNewTab( tabModelSelector.openNewTab(
...@@ -73,6 +80,12 @@ public class FeedStreamSurface implements FeedActionHandler { ...@@ -73,6 +80,12 @@ public class FeedStreamSurface implements FeedActionHandler {
FeedStreamSurfaceJni.get().loadMore(mNativeFeedStreamSurface, FeedStreamSurface.this); FeedStreamSurfaceJni.get().loadMore(mNativeFeedStreamSurface, FeedStreamSurface.this);
} }
@Override
public void processThereAndBackAgainData(byte[] data) {
FeedStreamSurfaceJni.get().processThereAndBackAgain(
mNativeFeedStreamSurface, FeedStreamSurface.this, data);
}
@Override @Override
public int requestDismissal() { public int requestDismissal() {
// TODO(jianli): may need to pass parameters from UI. // TODO(jianli): may need to pass parameters from UI.
...@@ -94,14 +107,6 @@ public class FeedStreamSurface implements FeedActionHandler { ...@@ -94,14 +107,6 @@ public class FeedStreamSurface implements FeedActionHandler {
mNativeFeedStreamSurface, FeedStreamSurface.this, changeId); mNativeFeedStreamSurface, FeedStreamSurface.this, changeId);
} }
/**
* Handles uploading data for ThereAndBackAgain.
*/
public void processThereAndBackAgain(byte[] data) {
FeedStreamSurfaceJni.get().processThereAndBackAgain(
mNativeFeedStreamSurface, FeedStreamSurface.this, data);
}
/** /**
* Informs that the surface is opened. We can request the initial set of content now. Once * Informs that the surface is opened. We can request the initial set of content now. Once
* the content is available, onStreamUpdated will be called. * the content is available, onStreamUpdated will be called.
......
...@@ -378,7 +378,7 @@ if (enable_feed_in_chrome) { ...@@ -378,7 +378,7 @@ if (enable_feed_in_chrome) {
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/tooltip/BasicTooltipApi.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/tooltip/BasicTooltipApi.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/tooltip/BasicTooltipSupportedApi.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/tooltip/BasicTooltipSupportedApi.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/tooltip/FeedTooltipUtils.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/tooltip/FeedTooltipUtils.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedActionHandler.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedListContentManager.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedServiceBridge.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedServiceBridge.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java",
] ]
......
...@@ -10,8 +10,30 @@ package org.chromium.chrome.browser.xsurface; ...@@ -10,8 +10,30 @@ package org.chromium.chrome.browser.xsurface;
public interface FeedActionsHandler { public interface FeedActionsHandler {
String KEY = "FeedActions"; String KEY = "FeedActions";
/**
* Requests additional content to be loaded. Once the load is completed, onStreamUpdated will be
* called.
*/
void loadMore();
/** /**
* Sends data back to the server when content is clicked. * Sends data back to the server when content is clicked.
*/ */
void processThereAndBackAgainData(byte[] data); void processThereAndBackAgainData(byte[] data);
/**
* Requests to dismiss a card. A change ID will be returned and it can be used to commit or
* discard the change.
*/
int requestDismissal();
/**
* Commits a previous requested dismissal denoted by change ID.
*/
void commitDismissal(int changeId);
/**
* Discards a previous requested dismissal denoted by change ID.
*/
void discardDismissal(int changeId);
} }
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