Commit 1b34593a authored by bauerb's avatar bauerb Committed by Commit bot

Add an experimental standalone content suggestions UI.

The UI is hidden behind a feature flag that enables a menu item (which
uses innovative string compression techniques to avoid bloat due to
i18n) to open the standalone content suggestions UI.

While the activity and menu item are not meant to be shipped in an
enabled state, this will allow iterating on a content suggestions UI
outside of the NTP.

Review-Url: https://codereview.chromium.org/2593523005
Cr-Commit-Position: refs/heads/master@{#441980}
parent 27fa8964
...@@ -413,6 +413,12 @@ by a child template that "extends" this file. ...@@ -413,6 +413,12 @@ by a child template that "extends" this file.
android:hardwareAccelerated="false"> android:hardwareAccelerated="false">
</activity> </activity>
<activity android:name="org.chromium.chrome.browser.suggestions.ContentSuggestionsActivity"
android:theme="@style/FullscreenWhiteActivityTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
android:windowSoftInputMode="stateAlwaysHidden">
</activity>
<activity android:name="org.chromium.chrome.browser.sync.ui.PassphraseActivity" <activity android:name="org.chromium.chrome.browser.sync.ui.PassphraseActivity"
android:theme="@style/MainTheme" android:theme="@style/MainTheme"
android:autoRemoveFromRecents="true"> android:autoRemoveFromRecents="true">
......
...@@ -70,6 +70,8 @@ ...@@ -70,6 +70,8 @@
android:title="@string/menu_help" /> android:title="@string/menu_help" />
<item android:id="@+id/enter_vr_id" <item android:id="@+id/enter_vr_id"
android:title="@string/enter_vr" /> android:title="@string/enter_vr" />
<item android:id="@+id/content_suggestions_standalone_ui"
android:title="@string/content_suggestions_standalone_ui" />
</group> </group>
<!-- Items shown only in the tab switcher --> <!-- Items shown only in the tab switcher -->
......
...@@ -68,6 +68,7 @@ public abstract class ChromeFeatureList { ...@@ -68,6 +68,7 @@ public abstract class ChromeFeatureList {
public static final String NTP_SNIPPETS_SAVE_TO_OFFLINE = "NTPSaveToOffline"; public static final String NTP_SNIPPETS_SAVE_TO_OFFLINE = "NTPSaveToOffline";
public static final String NTP_SNIPPETS_OFFLINE_BADGE = "NTPOfflineBadge"; public static final String NTP_SNIPPETS_OFFLINE_BADGE = "NTPOfflineBadge";
public static final String NTP_SUGGESTIONS_SECTION_DISMISSAL = "NTPSuggestionsSectionDismissal"; public static final String NTP_SUGGESTIONS_SECTION_DISMISSAL = "NTPSuggestionsSectionDismissal";
public static final String NTP_SUGGESTIONS_STANDALONE_UI = "NTPSuggestionsStandaloneUI";
public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps"; public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps";
public static final String TAB_REPARENTING = "TabReparenting"; public static final String TAB_REPARENTING = "TabReparenting";
public static final String VR_SHELL = "VrShell"; public static final String VR_SHELL = "VrShell";
......
...@@ -91,6 +91,7 @@ import org.chromium.chrome.browser.preferences.PrefServiceBridge; ...@@ -91,6 +91,7 @@ import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.preferences.datareduction.DataReductionPromoScreen; import org.chromium.chrome.browser.preferences.datareduction.DataReductionPromoScreen;
import org.chromium.chrome.browser.signin.SigninPromoUtil; import org.chromium.chrome.browser.signin.SigninPromoUtil;
import org.chromium.chrome.browser.snackbar.undo.UndoBarController; import org.chromium.chrome.browser.snackbar.undo.UndoBarController;
import org.chromium.chrome.browser.suggestions.ContentSuggestionsActivity;
import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate; import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabDelegateFactory; import org.chromium.chrome.browser.tab.TabDelegateFactory;
...@@ -1210,6 +1211,8 @@ public class ChromeTabbedActivity extends ChromeActivity implements OverviewMode ...@@ -1210,6 +1211,8 @@ public class ChromeTabbedActivity extends ChromeActivity implements OverviewMode
RecordUserAction.record("MobileTabClosedUndoShortCut"); RecordUserAction.record("MobileTabClosedUndoShortCut");
} else if (id == R.id.enter_vr_id) { } else if (id == R.id.enter_vr_id) {
mVrShellDelegate.enterVRIfNecessary(); mVrShellDelegate.enterVRIfNecessary();
} else if (id == R.id.content_suggestions_standalone_ui) {
ContentSuggestionsActivity.launch(getApplicationContext());
} else { } else {
return super.onMenuOrKeyboardAction(id, fromMenu); return super.onMenuOrKeyboardAction(id, fromMenu);
} }
......
...@@ -13,6 +13,7 @@ import org.chromium.base.ApiCompatibilityUtils; ...@@ -13,6 +13,7 @@ import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.CommandLine; import org.chromium.base.CommandLine;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.ShortcutHelper;
import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.UrlConstants;
...@@ -188,6 +189,11 @@ public class AppMenuPropertiesDelegate { ...@@ -188,6 +189,11 @@ public class AppMenuPropertiesDelegate {
// Only display the Enter VR button if VR Shell Dev environment is enabled. // Only display the Enter VR button if VR Shell Dev environment is enabled.
menu.findItem(R.id.enter_vr_id).setVisible( menu.findItem(R.id.enter_vr_id).setVisible(
CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_VR_SHELL_DEV)); CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_VR_SHELL_DEV));
// Only display the standalone content suggestions UI if the corresponding feature
// is enabled.
menu.findItem(R.id.content_suggestions_standalone_ui).setVisible(
ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SUGGESTIONS_STANDALONE_UI));
} }
if (isOverviewMenu) { if (isOverviewMenu) {
......
...@@ -17,7 +17,6 @@ import org.chromium.chrome.R; ...@@ -17,7 +17,6 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig; import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig;
import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.ui.base.WindowAndroid.OnCloseContextMenuListener; import org.chromium.ui.base.WindowAndroid.OnCloseContextMenuListener;
import org.chromium.ui.mojom.WindowOpenDisposition; import org.chromium.ui.mojom.WindowOpenDisposition;
...@@ -43,9 +42,10 @@ public class ContextMenuManager implements OnCloseContextMenuListener { ...@@ -43,9 +42,10 @@ public class ContextMenuManager implements OnCloseContextMenuListener {
public static final int ID_SAVE_FOR_OFFLINE = 3; public static final int ID_SAVE_FOR_OFFLINE = 3;
public static final int ID_REMOVE = 4; public static final int ID_REMOVE = 4;
private final Activity mActivity;
private final NewTabPageManager mManager; private final NewTabPageManager mManager;
private final Tab mTab;
private final TouchDisableableView mOuterView; private final TouchDisableableView mOuterView;
private boolean mContextMenuOpen;
/** Defines callback to configure the context menu and respond to user interaction. */ /** Defines callback to configure the context menu and respond to user interaction. */
public interface Delegate { public interface Delegate {
...@@ -65,10 +65,10 @@ public class ContextMenuManager implements OnCloseContextMenuListener { ...@@ -65,10 +65,10 @@ public class ContextMenuManager implements OnCloseContextMenuListener {
/** Interface for a view that can be set to stop responding to touches. */ /** Interface for a view that can be set to stop responding to touches. */
public interface TouchDisableableView { void setTouchEnabled(boolean enabled); } public interface TouchDisableableView { void setTouchEnabled(boolean enabled); }
public ContextMenuManager( public ContextMenuManager(Activity activity, NewTabPageManager newTabPageManager,
NewTabPageManager newTabPageManager, Tab tab, TouchDisableableView outerView) { TouchDisableableView outerView) {
mActivity = activity;
mManager = newTabPageManager; mManager = newTabPageManager;
mTab = tab;
mOuterView = outerView; mOuterView = outerView;
} }
...@@ -111,22 +111,19 @@ public class ContextMenuManager implements OnCloseContextMenuListener { ...@@ -111,22 +111,19 @@ public class ContextMenuManager implements OnCloseContextMenuListener {
// or swiping to dismiss an item (eg. https://crbug.com/638854, https://crbug.com/638555, // or swiping to dismiss an item (eg. https://crbug.com/638854, https://crbug.com/638555,
// https://crbug.com/636296) // https://crbug.com/636296)
mOuterView.setTouchEnabled(false); mOuterView.setTouchEnabled(false);
mContextMenuOpen = true;
mTab.getWindowAndroid().addContextMenuCloseListener(this);
} }
@Override @Override
public void onContextMenuClosed() { public void onContextMenuClosed() {
if (!mContextMenuOpen) return;
mOuterView.setTouchEnabled(true); mOuterView.setTouchEnabled(true);
mTab.getWindowAndroid().removeContextMenuCloseListener(this); mContextMenuOpen = false;
} }
/** Closes the context menu, if open. */ /** Closes the context menu, if open. */
public void closeContextMenu() { public void closeContextMenu() {
Activity activity = mTab.getWindowAndroid().getActivity().get(); mActivity.closeContextMenu();
if (activity == null) return;
activity.closeContextMenu();
} }
private boolean shouldShowItem(@ContextMenuItemId int itemId, Delegate delegate) { private boolean shouldShowItem(@ContextMenuItemId int itemId, Delegate delegate) {
......
...@@ -361,8 +361,15 @@ public class NewTabPageView extends FrameLayout ...@@ -361,8 +361,15 @@ public class NewTabPageView extends FrameLayout
mScrollView.enableBottomShadow(SHADOW_COLOR); mScrollView.enableBottomShadow(SHADOW_COLOR);
mNewTabPageLayout = (NewTabPageLayout) findViewById(R.id.ntp_content); mNewTabPageLayout = (NewTabPageLayout) findViewById(R.id.ntp_content);
} }
mContextMenuManager = mContextMenuManager = new ContextMenuManager(mActivity, mManager,
new ContextMenuManager(mManager, tab, mUseCardsUi ? mRecyclerView : mScrollView); mUseCardsUi ? mRecyclerView : mScrollView);
mActivity.getWindowAndroid().addContextMenuCloseListener(mContextMenuManager);
manager.addDestructionObserver(new DestructionObserver() {
@Override
public void onDestroy() {
mActivity.getWindowAndroid().removeContextMenuCloseListener(mContextMenuManager);
}
});
mMostVisitedDesign = new MostVisitedDesign(getContext()); mMostVisitedDesign = new MostVisitedDesign(getContext());
mMostVisitedLayout = mMostVisitedLayout =
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.ntp.cards; package org.chromium.chrome.browser.ntp.cards;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter; import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
...@@ -27,32 +28,34 @@ import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; ...@@ -27,32 +28,34 @@ import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
*/ */
public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements NodeParent { public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements NodeParent {
private final NewTabPageManager mNewTabPageManager; private final NewTabPageManager mNewTabPageManager;
@Nullable
private final View mAboveTheFoldView; private final View mAboveTheFoldView;
private final UiConfig mUiConfig; private final UiConfig mUiConfig;
private NewTabPageRecyclerView mRecyclerView; private NewTabPageRecyclerView mRecyclerView;
private final InnerNode mRoot; private final InnerNode mRoot;
private final AboveTheFoldItem mAboveTheFold = new AboveTheFoldItem(); @Nullable
private final AboveTheFoldItem mAboveTheFold;
private final SectionList mSections; private final SectionList mSections;
private final SignInPromo mSigninPromo; private final SignInPromo mSigninPromo;
private final AllDismissedItem mAllDismissed; private final AllDismissedItem mAllDismissed;
private final Footer mFooter; private final Footer mFooter;
private final SpacingItem mBottomSpacer = new SpacingItem(); private final SpacingItem mBottomSpacer;
/** /**
* Creates the adapter that will manage all the cards to display on the NTP. * Creates the adapter that will manage all the cards to display on the NTP.
* *
* @param manager the NewTabPageManager to use to interact with the rest of the system. * @param manager the NewTabPageManager to use to interact with the rest of the system.
* @param aboveTheFoldView the layout encapsulating all the above-the-fold elements * @param aboveTheFoldView the layout encapsulating all the above-the-fold elements
* (logo, search box, most visited tiles) * (logo, search box, most visited tiles), or null if only suggestions should
* be displayed.
* @param uiConfig the NTP UI configuration, to be passed to created views. * @param uiConfig the NTP UI configuration, to be passed to created views.
* @param offlinePageBridge the OfflinePageBridge used to determine if articles are available * @param offlinePageBridge the OfflinePageBridge used to determine if articles are available
* offline. * offline.
*
*/ */
public NewTabPageAdapter(NewTabPageManager manager, View aboveTheFoldView, UiConfig uiConfig, public NewTabPageAdapter(NewTabPageManager manager, @Nullable View aboveTheFoldView,
OfflinePageBridge offlinePageBridge) { UiConfig uiConfig, OfflinePageBridge offlinePageBridge) {
mNewTabPageManager = manager; mNewTabPageManager = manager;
mAboveTheFoldView = aboveTheFoldView; mAboveTheFoldView = aboveTheFoldView;
mUiConfig = uiConfig; mUiConfig = uiConfig;
...@@ -63,8 +66,19 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements ...@@ -63,8 +66,19 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements
mAllDismissed = new AllDismissedItem(); mAllDismissed = new AllDismissedItem();
mFooter = new Footer(); mFooter = new Footer();
mRoot.addChildren( if (mAboveTheFoldView == null) {
mAboveTheFold, mSections, mSigninPromo, mAllDismissed, mFooter, mBottomSpacer); mAboveTheFold = null;
} else {
mAboveTheFold = new AboveTheFoldItem();
mRoot.addChild(mAboveTheFold);
}
mRoot.addChildren(mSections, mSigninPromo, mAllDismissed, mFooter);
if (mAboveTheFoldView == null) {
mBottomSpacer = null;
} else {
mBottomSpacer = new SpacingItem();
mRoot.addChild(mBottomSpacer);
}
updateAllDismissedVisibility(); updateAllDismissedVisibility();
mRoot.setParent(this); mRoot.setParent(this);
...@@ -127,6 +141,8 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements ...@@ -127,6 +141,8 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements
} }
public int getAboveTheFoldPosition() { public int getAboveTheFoldPosition() {
if (mAboveTheFoldView == null) return RecyclerView.NO_POSITION;
return getChildPositionOffset(mAboveTheFold); return getChildPositionOffset(mAboveTheFold);
} }
...@@ -146,6 +162,8 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements ...@@ -146,6 +162,8 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements
} }
int getBottomSpacerPosition() { int getBottomSpacerPosition() {
if (mBottomSpacer == null) return RecyclerView.NO_POSITION;
return getChildPositionOffset(mBottomSpacer); return getChildPositionOffset(mBottomSpacer);
} }
...@@ -165,7 +183,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements ...@@ -165,7 +183,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements
public void onItemRangeInserted(TreeNode child, int itemPosition, int itemCount) { public void onItemRangeInserted(TreeNode child, int itemPosition, int itemCount) {
assert child == mRoot; assert child == mRoot;
notifyItemRangeInserted(itemPosition, itemCount); notifyItemRangeInserted(itemPosition, itemCount);
mBottomSpacer.refresh(); if (mBottomSpacer != null) mBottomSpacer.refresh();
updateAllDismissedVisibility(); updateAllDismissedVisibility();
} }
...@@ -174,7 +192,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements ...@@ -174,7 +192,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements
public void onItemRangeRemoved(TreeNode child, int itemPosition, int itemCount) { public void onItemRangeRemoved(TreeNode child, int itemPosition, int itemCount) {
assert child == mRoot; assert child == mRoot;
notifyItemRangeRemoved(itemPosition, itemCount); notifyItemRangeRemoved(itemPosition, itemCount);
mBottomSpacer.refresh(); if (mBottomSpacer != null) mBottomSpacer.refresh();
updateAllDismissedVisibility(); updateAllDismissedVisibility();
} }
......
// Copyright 2016 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.suggestions;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import org.chromium.base.Callback;
import org.chromium.base.ObserverList;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.SynchronousInitializationActivity;
import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallback;
import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
import org.chromium.chrome.browser.ntp.ContextMenuManager;
import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver;
import org.chromium.chrome.browser.ntp.MostVisitedItem;
import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
import org.chromium.chrome.browser.ntp.UiConfig;
import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObserver;
import org.chromium.chrome.browser.profiles.Profile;
import java.util.Set;
/**
* Experimental activity to show content suggestions outside of the New Tab Page.
*/
public class ContentSuggestionsActivity extends SynchronousInitializationActivity {
private final ObserverList<DestructionObserver> mDestructionObservers = new ObserverList<>();
private ContextMenuManager mContextMenuManager;
private SnippetsBridge mSnippetsBridge;
private NewTabPageRecyclerView mRecyclerView;
public static void launch(Context context) {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(context, ContentSuggestionsActivity.class);
context.startActivity(intent);
}
private class SuggestionsNewTabPageManager implements NewTabPageManager {
@Override
public void removeMostVisitedItem(MostVisitedItem item) {}
@Override
public void openMostVisitedItem(int windowDisposition, MostVisitedItem item) {}
@Override
public boolean isLocationBarShownInNTP() {
return false;
}
@Override
public boolean isVoiceSearchEnabled() {
return false;
}
@Override
public boolean isFakeOmniboxTextEnabledTablet() {
return false;
}
@Override
public boolean isOpenInNewWindowEnabled() {
return true;
}
@Override
public boolean isOpenInIncognitoEnabled() {
return true;
}
@Override
public void navigateToBookmarks() {}
@Override
public void navigateToRecentTabs() {}
@Override
public void navigateToDownloadManager() {}
@Override
public void trackSnippetsPageImpression(int[] categories, int[] suggestionsPerCategory) {}
@Override
public void trackSnippetImpression(SnippetArticle article) {}
@Override
public void trackSnippetMenuOpened(SnippetArticle article) {}
@Override
public void trackSnippetCategoryActionImpression(int category, int position) {}
@Override
public void trackSnippetCategoryActionClick(int category, int position) {}
@Override
public void openSnippet(int windowOpenDisposition, SnippetArticle article) {}
@Override
public void focusSearchBox(boolean beginVoiceSearch, String pastedText) {}
@Override
public void setMostVisitedURLsObserver(MostVisitedURLsObserver observer, int numResults) {}
@Override
public void getLocalFaviconImageForURL(
String url, int size, FaviconImageCallback faviconCallback) {}
@Override
public void getLargeIconForUrl(String url, int size, LargeIconCallback callback) {}
@Override
public void ensureIconIsAvailable(String pageUrl, String iconUrl, boolean isLargeIcon,
boolean isTemporary, IconAvailabilityCallback callback) {}
@Override
public void getUrlsAvailableOffline(Set<String> pageUrls, Callback<Set<String>> callback) {}
@Override
public void onLogoClicked(boolean isAnimatedLogoShowing) {}
@Override
public void getSearchProviderLogo(LogoObserver logoObserver) {}
@Override
public void onLoadingComplete(MostVisitedItem[] mostVisitedItems) {}
@Override
public void onLearnMoreClicked() {}
@Override
public SuggestionsSource getSuggestionsSource() {
return mSnippetsBridge;
}
@Override
public void addDestructionObserver(DestructionObserver destructionObserver) {
mDestructionObservers.addObserver(destructionObserver);
}
@Override
public boolean isCurrentPage() {
return true;
}
@Override
public ContextMenuManager getContextMenuManager() {
return mContextMenuManager;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
assert ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SUGGESTIONS_STANDALONE_UI);
mRecyclerView = (NewTabPageRecyclerView) LayoutInflater.from(this).inflate(
R.layout.new_tab_page_recycler_view, null, false);
Profile profile = Profile.getLastUsedProfile();
mSnippetsBridge = new SnippetsBridge(profile);
NewTabPageManager manager = new SuggestionsNewTabPageManager();
mContextMenuManager = new ContextMenuManager(this, manager, mRecyclerView);
UiConfig uiConfig = new UiConfig(mRecyclerView);
NewTabPageAdapter adapter = new NewTabPageAdapter(
manager, null, uiConfig, OfflinePageBridge.getForProfile(profile));
mRecyclerView.setAdapter(adapter);
mRecyclerView.setUpSwipeToDismiss();
setContentView(mRecyclerView);
}
@Override
public void onContextMenuClosed(Menu menu) {
mContextMenuManager.onContextMenuClosed();
}
@Override
protected void onDestroy() {
for (DestructionObserver observer : mDestructionObservers) {
observer.onDestroy();
}
super.onDestroy();
}
}
file://chrome/android/java/src/org/chromium/chrome/browser/ntp/OWNERS
\ No newline at end of file
...@@ -2877,6 +2877,11 @@ You can control the Physical Web in Chrome Settings. ...@@ -2877,6 +2877,11 @@ You can control the Physical Web in Chrome Settings.
<message name="IDS_KEYBOARD_SHORTCUT_WEBPAGE_GROUP_HEADER" desc="A text label that appears above a list of shortcuts that are related to manipulation of the current tab window. This group is part of several groups of keyboard shortcuts all shown in a dialog."> <message name="IDS_KEYBOARD_SHORTCUT_WEBPAGE_GROUP_HEADER" desc="A text label that appears above a list of shortcuts that are related to manipulation of the current tab window. This group is part of several groups of keyboard shortcuts all shown in a dialog.">
Webpage shortcuts Webpage shortcuts
</message> </message>
<!-- Content suggestion strings -->
<message name="IDS_CONTENT_SUGGESTIONS_STANDALONE_UI" desc="A text label for the menu item to open the content suggestions standalone UI." translateable="false">
🔰🆕👌
</message>
</messages> </messages>
</release> </release>
</grit> </grit>
...@@ -919,6 +919,7 @@ chrome_java_sources = [ ...@@ -919,6 +919,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/snackbar/smartlockautosignin/AutoSigninSnackbarController.java", "java/src/org/chromium/chrome/browser/snackbar/smartlockautosignin/AutoSigninSnackbarController.java",
"java/src/org/chromium/chrome/browser/snackbar/undo/UndoBarController.java", "java/src/org/chromium/chrome/browser/snackbar/undo/UndoBarController.java",
"java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java", "java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java",
"java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java",
"java/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProvider.java", "java/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProvider.java",
"java/src/org/chromium/chrome/browser/sync/GmsCoreSyncListener.java", "java/src/org/chromium/chrome/browser/sync/GmsCoreSyncListener.java",
"java/src/org/chromium/chrome/browser/sync/GoogleServiceAuthError.java", "java/src/org/chromium/chrome/browser/sync/GoogleServiceAuthError.java",
......
...@@ -210,7 +210,8 @@ public class ArticleSnippetsTest extends ChromeActivityTestCaseBase<ChromeActivi ...@@ -210,7 +210,8 @@ public class ArticleSnippetsTest extends ChromeActivityTestCaseBase<ChromeActivi
*/ */
private class MockNewTabPageManager implements NewTabPageManager { private class MockNewTabPageManager implements NewTabPageManager {
// TODO(dgn): provide a RecyclerView if we need to test the context menu. // TODO(dgn): provide a RecyclerView if we need to test the context menu.
private ContextMenuManager mContextMenuManager = new ContextMenuManager(this, null, null); private ContextMenuManager mContextMenuManager =
new ContextMenuManager(getActivity(), this, null);
@Override @Override
public void getLocalFaviconImageForURL( public void getLocalFaviconImageForURL(
......
...@@ -29,6 +29,7 @@ import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils. ...@@ -29,6 +29,7 @@ import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.
import android.content.res.Resources; import android.content.res.Resources;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.AdapterDataObserver; import android.support.v7.widget.RecyclerView.AdapterDataObserver;
import android.view.View;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
...@@ -971,7 +972,8 @@ public class NewTabPageAdapterTest { ...@@ -971,7 +972,8 @@ public class NewTabPageAdapterTest {
} }
private void reloadNtp() { private void reloadNtp() {
mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); mAdapter = new NewTabPageAdapter(mNewTabPageManager, mock(View.class), null,
mOfflinePageBridge);
} }
private void assertArticlesEqual(List<SnippetArticle> articles, int start, int end) { private void assertArticlesEqual(List<SnippetArticle> articles, int start, int end) {
......
...@@ -51,6 +51,7 @@ const base::Feature* kFeaturesExposedToJava[] = { ...@@ -51,6 +51,7 @@ const base::Feature* kFeaturesExposedToJava[] = {
&kNoCreditCardAbort, &kNoCreditCardAbort,
&kNTPFakeOmniboxTextFeature, &kNTPFakeOmniboxTextFeature,
&kNTPOfflinePagesFeature, &kNTPOfflinePagesFeature,
&kNTPSuggestionsStandaloneUIFeature,
&kPhysicalWebFeature, &kPhysicalWebFeature,
&kPhysicalWebIgnoreOtherClientsFeature, &kPhysicalWebIgnoreOtherClientsFeature,
&kSpecialLocaleFeature, &kSpecialLocaleFeature,
...@@ -113,6 +114,9 @@ const base::Feature kNTPFakeOmniboxTextFeature{ ...@@ -113,6 +114,9 @@ const base::Feature kNTPFakeOmniboxTextFeature{
const base::Feature kNTPOfflinePagesFeature{"NTPOfflinePages", const base::Feature kNTPOfflinePagesFeature{"NTPOfflinePages",
base::FEATURE_ENABLED_BY_DEFAULT}; base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kNTPSuggestionsStandaloneUIFeature{
"NTPSuggestionsStandaloneUI", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kPhysicalWebFeature{"PhysicalWeb", const base::Feature kPhysicalWebFeature{"PhysicalWeb",
base::FEATURE_ENABLED_BY_DEFAULT}; base::FEATURE_ENABLED_BY_DEFAULT};
......
...@@ -26,6 +26,7 @@ extern const base::Feature kNativeAndroidHistoryManager; ...@@ -26,6 +26,7 @@ extern const base::Feature kNativeAndroidHistoryManager;
extern const base::Feature kNoCreditCardAbort; extern const base::Feature kNoCreditCardAbort;
extern const base::Feature kNTPFakeOmniboxTextFeature; extern const base::Feature kNTPFakeOmniboxTextFeature;
extern const base::Feature kNTPOfflinePagesFeature; extern const base::Feature kNTPOfflinePagesFeature;
extern const base::Feature kNTPSuggestionsStandaloneUIFeature;
extern const base::Feature kPhysicalWebFeature; extern const base::Feature kPhysicalWebFeature;
extern const base::Feature kPhysicalWebIgnoreOtherClientsFeature; extern const base::Feature kPhysicalWebIgnoreOtherClientsFeature;
extern const base::Feature kSpecialLocaleFeature; extern const base::Feature kSpecialLocaleFeature;
......
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