Commit fe13c749 authored by Natalie Chouinard's avatar Natalie Chouinard Committed by Commit Bot

Revert "[StartSurface] Implement explore surface with feeds"

This reverts commit a076c4e2.

Reason for revert:
Compile failure List of errors:
../../chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java:147: error: cannot find symbol

Original change's description:
> [StartSurface] Implement explore surface with feeds
> 
> Screenshots:
> https://drive.google.com/file/d/14ssIg6-tvLU_yAa8RTZEPHNsvbfGYgTa/view?usp=sharing
> 
> This CL split the original FeedNewTabPage, FeedNewTabPageMediator and StreamLifecycleManager
> into multiple classes, but we do not expect visible changes on FeedNewTabPage.
> 
> This CL also fixed the dummy FeedNewTabPage which was broken by
> https://chromium-review.googlesource.com/c/chromium/src/+/1709731
> 
> Bug: 982018
> Change-Id: I933cb01789d5eda8a196de00e4bf279bb7d6d785
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1715410
> Reviewed-by: David Trainor <dtrainor@chromium.org>
> Reviewed-by: Sky Malice <skym@chromium.org>
> Commit-Queue: David Trainor <dtrainor@chromium.org>
> Commit-Queue: Ganggui Tang <gogerald@chromium.org>
> Auto-Submit: Ganggui Tang <gogerald@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#681412}

TBR=dtrainor@chromium.org,yusufo@chromium.org,gogerald@chromium.org,skym@chromium.org

Change-Id: I6af1d483fc1b912d1b60d2ba9b7280125c65b410
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 982018
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1721000Reviewed-by: default avatarNatalie Chouinard <chouinard@chromium.org>
Commit-Queue: Natalie Chouinard <chouinard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#681427}
parent 21dd8c10
include_rules = [
"+content/public/android/java/src/org/chromium/content_public",
]
\ No newline at end of file
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import("//build/config/android/rules.gni") import("//build/config/android/rules.gni")
import("//chrome/common/features.gni") import("//chrome/common/features.gni")
import("//components/feed/features.gni")
java_strings_grd("java_strings_grd") { java_strings_grd("java_strings_grd") {
defines = chrome_grit_defines defines = chrome_grit_defines
...@@ -78,13 +77,14 @@ android_resources("java_resources") { ...@@ -78,13 +77,14 @@ android_resources("java_resources") {
android_library("java") { android_library("java") {
java_files = [ java_files = [
"java/src/org/chromium/chrome/features/start_surface/BottomBarCoordinator.java", "java/src/org/chromium/chrome/features/start_surface/BottomBarCoordinator.java",
"java/src/org/chromium/chrome/features/start_surface/BottomBarProperties.java",
"java/src/org/chromium/chrome/features/start_surface/BottomBarView.java", "java/src/org/chromium/chrome/features/start_surface/BottomBarView.java",
"java/src/org/chromium/chrome/features/start_surface/BottomBarViewBinder.java", "java/src/org/chromium/chrome/features/start_surface/BottomBarViewBinder.java",
"java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java",
"java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java", "java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java",
"java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java", "java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java",
"java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java", "java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java",
"java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java", "java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java",
"java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java",
] ]
deps = [ deps = [
...@@ -95,25 +95,4 @@ android_library("java") { ...@@ -95,25 +95,4 @@ android_library("java") {
"//third_party/android_deps:com_android_support_design_java", "//third_party/android_deps:com_android_support_design_java",
"//ui/android:ui_full_java", "//ui/android:ui_full_java",
] ]
if (enable_feed_in_chrome) {
java_files += [
"java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceActionHandler.java",
"java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java",
"java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceNavigationDelegate.java",
"java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceStreamLifecycleManager.java",
"java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java",
]
deps += [
"//chrome/android/public/profiles:java",
"//content/public/android:content_java",
"//third_party/custom_tabs_client:custom_tabs_support_java",
"//third_party/feed:feed_lib_java",
"//ui/android:ui_utils_java",
"//ui/base/mojom:mojom_java",
]
} else {
java_files += [ "dummy/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java" ]
}
} }
// Copyright 2019 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.features.start_surface;
import android.view.ViewGroup;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.ui.modelutil.PropertyModel;
/** The dummy coordinator when feed is not enabled ('src/components/feed/features.gni'). */
class ExploreSurfaceCoordinator {
ExploreSurfaceCoordinator(ChromeActivity activity, ViewGroup parentView,
int bottomControlsHeight, PropertyModel containerPropertyModel) {}
}
\ No newline at end of file
...@@ -4,25 +4,59 @@ ...@@ -4,25 +4,59 @@
package org.chromium.chrome.features.start_surface; package org.chromium.chrome.features.start_surface;
import static org.chromium.chrome.features.start_surface.BottomBarProperties.IS_INCOGNITO;
import static org.chromium.chrome.features.start_surface.BottomBarProperties.IS_VISIBLE;
import static org.chromium.chrome.features.start_surface.BottomBarProperties.ON_CLICK_LISTENER;
import android.content.Context; import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.start_surface.R; import org.chromium.chrome.start_surface.R;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor; import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
/** The coordinator to control the bottom bar. */ /** The coordinator to control the bottom bar. */
class BottomBarCoordinator { class BottomBarCoordinator {
private final PropertyModel mBottomBarPropertyModel;
private final PropertyModelChangeProcessor mBottomBarChangeProcessor; private final PropertyModelChangeProcessor mBottomBarChangeProcessor;
BottomBarCoordinator( BottomBarCoordinator(Context context, ViewGroup parentView, TabModelSelector tabModelSelector) {
Context context, ViewGroup parentView, PropertyModel containerPropertyModel) {
BottomBarView bottomBarView = BottomBarView bottomBarView =
(BottomBarView) LayoutInflater.from(context) (BottomBarView) LayoutInflater.from(context)
.inflate(R.layout.ss_bottom_bar_layout, parentView, true) .inflate(R.layout.ss_bottom_bar_layout, parentView, true)
.findViewById(R.id.ss_bottom_bar); .findViewById(R.id.ss_bottom_bar);
mBottomBarPropertyModel = new PropertyModel(BottomBarProperties.ALL_KEYS);
mBottomBarChangeProcessor = PropertyModelChangeProcessor.create( mBottomBarChangeProcessor = PropertyModelChangeProcessor.create(
containerPropertyModel, bottomBarView, BottomBarViewBinder::bind); mBottomBarPropertyModel, bottomBarView, BottomBarViewBinder::bind);
tabModelSelector.addObserver(new EmptyTabModelSelectorObserver() {
@Override
public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
mBottomBarPropertyModel.set(IS_INCOGNITO, newModel.isIncognito());
}
});
// Set the initial state.
mBottomBarPropertyModel.set(IS_INCOGNITO, tabModelSelector.isIncognitoSelected());
}
/**
* Set the visibility of this bottom bar.
* @param shown Whether sets the visibility to visible or not.
*/
public void setVisibility(boolean shown) {
mBottomBarPropertyModel.set(IS_VISIBLE, shown);
}
/**
* Set the {@link BottomBarProperties.OnClickListener}.
* @param listener Listen clicks.
*/
public void setOnClickListener(BottomBarProperties.OnClickListener listener) {
mBottomBarPropertyModel.set(ON_CLICK_LISTENER, listener);
} }
} }
\ No newline at end of file
...@@ -7,9 +7,9 @@ package org.chromium.chrome.features.start_surface; ...@@ -7,9 +7,9 @@ package org.chromium.chrome.features.start_surface;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
/** List of the start surface properties. */ /** List of the bottom bar properties. */
class StartSurfaceProperties { class BottomBarProperties {
public static interface BottomBarClickListener { public static interface OnClickListener {
/** /**
* Called when clicks on the home button. * Called when clicks on the home button.
* */ * */
...@@ -20,16 +20,13 @@ class StartSurfaceProperties { ...@@ -20,16 +20,13 @@ class StartSurfaceProperties {
* */ * */
void onExploreButtonClicked(); void onExploreButtonClicked();
} }
public static final PropertyModel
.WritableObjectPropertyKey<BottomBarClickListener> BottomBarClickListener =
new PropertyModel.WritableObjectPropertyKey<BottomBarClickListener>();
public static final PropertyModel.WritableBooleanPropertyKey IS_EXPLORE_SURFACE_VISIBLE =
new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel.WritableBooleanPropertyKey IS_INCOGNITO = public static final PropertyModel.WritableBooleanPropertyKey IS_INCOGNITO =
new PropertyModel.WritableBooleanPropertyKey(); new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel.WritableBooleanPropertyKey IS_SHOWING_OVERVIEW = public static final PropertyModel.WritableBooleanPropertyKey IS_VISIBLE =
new PropertyModel.WritableBooleanPropertyKey(); new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel.WritableObjectPropertyKey<OnClickListener> ON_CLICK_LISTENER =
new PropertyModel.WritableObjectPropertyKey<OnClickListener>();
public static final PropertyKey[] ALL_KEYS = new PropertyKey[] { public static final PropertyKey[] ALL_KEYS =
BottomBarClickListener, IS_EXPLORE_SURFACE_VISIBLE, IS_INCOGNITO, IS_SHOWING_OVERVIEW}; new PropertyKey[] {IS_INCOGNITO, IS_VISIBLE, ON_CLICK_LISTENER};
} }
\ No newline at end of file
...@@ -32,7 +32,7 @@ class BottomBarView extends FrameLayout { ...@@ -32,7 +32,7 @@ class BottomBarView extends FrameLayout {
private TextView mHomeButtonLabel; private TextView mHomeButtonLabel;
private ChromeImageView mExploreButton; private ChromeImageView mExploreButton;
private TextView mExploreButtonLabel; private TextView mExploreButtonLabel;
private StartSurfaceProperties.BottomBarClickListener mOnClickListener; private BottomBarProperties.OnClickListener mOnClickListener;
public BottomBarView(Context context, AttributeSet attrs) { public BottomBarView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
...@@ -84,7 +84,7 @@ class BottomBarView extends FrameLayout { ...@@ -84,7 +84,7 @@ class BottomBarView extends FrameLayout {
/** /**
* Set the incognito state. * Set the incognito state.
* @param isIncognito Whether is in incognito mode. * @param isIncognito Whether is setting the incognito mode.
*/ */
public void setIncognito(boolean isIncognito) { public void setIncognito(boolean isIncognito) {
// TODO(crbug.com/982018): Support dark mode. // TODO(crbug.com/982018): Support dark mode.
...@@ -115,10 +115,10 @@ class BottomBarView extends FrameLayout { ...@@ -115,10 +115,10 @@ class BottomBarView extends FrameLayout {
} }
/** /**
* Set the {@link StartSurfaceProperties.BottomBarClickListener}. * Set the {@link BottomBarProperties.OnClickListener}.
* @param listener Listen clicks. * @param listener Listen clicks.
*/ */
public void setOnClickListener(StartSurfaceProperties.BottomBarClickListener listener) { public void setOnClickListener(BottomBarProperties.OnClickListener listener) {
mOnClickListener = listener; mOnClickListener = listener;
} }
} }
\ No newline at end of file
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
package org.chromium.chrome.features.start_surface; package org.chromium.chrome.features.start_surface;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.BottomBarClickListener; import static org.chromium.chrome.features.start_surface.BottomBarProperties.IS_INCOGNITO;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_INCOGNITO; import static org.chromium.chrome.features.start_surface.BottomBarProperties.IS_VISIBLE;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW; import static org.chromium.chrome.features.start_surface.BottomBarProperties.ON_CLICK_LISTENER;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
...@@ -16,10 +16,10 @@ class BottomBarViewBinder { ...@@ -16,10 +16,10 @@ class BottomBarViewBinder {
public static void bind(PropertyModel model, BottomBarView view, PropertyKey propertyKey) { public static void bind(PropertyModel model, BottomBarView view, PropertyKey propertyKey) {
if (IS_INCOGNITO == propertyKey) { if (IS_INCOGNITO == propertyKey) {
view.setIncognito(model.get(IS_INCOGNITO)); view.setIncognito(model.get(IS_INCOGNITO));
} else if (IS_SHOWING_OVERVIEW == propertyKey) { } else if (IS_VISIBLE == propertyKey) {
view.setVisibility(model.get(IS_SHOWING_OVERVIEW)); view.setVisibility(model.get(IS_VISIBLE));
} else if (BottomBarClickListener == propertyKey) { } else if (ON_CLICK_LISTENER == propertyKey) {
view.setOnClickListener(model.get(BottomBarClickListener)); view.setOnClickListener(model.get(ON_CLICK_LISTENER));
} }
} }
} }
\ No newline at end of file
// Copyright 2019 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.features.start_surface;
import android.support.annotation.NonNull;
import com.google.android.libraries.feed.api.client.knowncontent.ContentMetadata;
import org.chromium.chrome.browser.feed.FeedLoggingBridge;
import org.chromium.chrome.browser.feed.FeedOfflineIndicator;
import org.chromium.chrome.browser.feed.action.FeedActionHandler;
import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate;
import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
/** Implementation of the {@link ActionApi} for the explore surface. */
class ExploreSurfaceActionHandler extends FeedActionHandler {
ExploreSurfaceActionHandler(@NonNull NativePageNavigationDelegate delegate,
@NonNull Runnable suggestionConsumedObserver,
@NonNull FeedOfflineIndicator offlineIndicator,
@NonNull OfflinePageBridge offlinePageBridge,
@NonNull FeedLoggingBridge loggingBridge) {
super(delegate, suggestionConsumedObserver, offlineIndicator, offlinePageBridge,
loggingBridge);
}
// TODO(crbug.com/982018): Support download and lean more actions.
@Override
public void downloadUrl(ContentMetadata contentMetadata) {}
@Override
public boolean canDownloadUrl() {
return false;
}
@Override
public void learnMore() {}
@Override
public boolean canLearnMore() {
return false;
}
}
\ No newline at end of file
...@@ -4,77 +4,7 @@ ...@@ -4,77 +4,7 @@
package org.chromium.chrome.features.start_surface; package org.chromium.chrome.features.start_surface;
import android.app.Activity;
import android.view.MotionEvent;
import android.view.ViewGroup;
import com.google.android.libraries.feed.api.client.stream.Stream;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.feed.FeedProcessScopeFactory;
import org.chromium.chrome.browser.feed.FeedSurfaceCoordinator;
import org.chromium.chrome.browser.feed.StreamLifecycleManager;
import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
import org.chromium.chrome.start_surface.R;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
/** The coordinator to control the explore surface. */ /** The coordinator to control the explore surface. */
class ExploreSurfaceCoordinator implements FeedSurfaceCoordinator.FeedSurfaceDelegate, class ExploreSurfaceCoordinator {
ExploreSurfaceViewBinder.FeedSurfaceDelegate { // TODO(crbug.com/982018): Implement the explore surface.
private final ChromeActivity mActivity;
private final PropertyModelChangeProcessor mPropertyModelChangeProcessor;
// mExploreSurfaceNavigationDelegate is lightweight, we keep it across FeedSurfaceCoordinators
// after creating it during the first show.
private ExploreSurfaceNavigationDelegate mExploreSurfaceNavigationDelegate;
ExploreSurfaceCoordinator(ChromeActivity activity, ViewGroup parentView,
int bottomControlsHeight, PropertyModel containerPropertyModel) {
mActivity = activity;
int toolbarHeight =
mActivity.getResources().getDimensionPixelSize(R.dimen.toolbar_height_no_shadow);
int topMargin = ReturnToChromeExperimentsUtil.shouldShowOmniboxOnTabSwitcher()
? toolbarHeight * 2
: toolbarHeight;
ExploreSurfaceViewBinder.ViewHolder viewHolder = new ExploreSurfaceViewBinder.ViewHolder(
parentView, bottomControlsHeight, topMargin, this);
mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(
containerPropertyModel, viewHolder, ExploreSurfaceViewBinder::bind);
}
// Implements FeedSurfaceCoordinator.FeedSurfaceDelegate.
@Override
public StreamLifecycleManager createStreamLifecycleManager(Stream stream, Activity activity) {
return new ExploreSurfaceStreamLifecycleManager(stream, activity);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
// Implements ExploreSurfaceViewBinder.FeedSurfaceDelegate.
@Override
public FeedSurfaceCoordinator createFeedSurfaceCoordinator(boolean isIncognito) {
if (mExploreSurfaceNavigationDelegate == null)
mExploreSurfaceNavigationDelegate = new ExploreSurfaceNavigationDelegate(mActivity);
mExploreSurfaceNavigationDelegate.setIncognito(isIncognito);
ExploreSurfaceActionHandler exploreSurfaceActionHandler =
new ExploreSurfaceActionHandler(mExploreSurfaceNavigationDelegate,
FeedProcessScopeFactory.getFeedConsumptionObserver(),
FeedProcessScopeFactory.getFeedOfflineIndicator(),
OfflinePageBridge.getForProfile(isIncognito
? Profile.getLastUsedProfile().getOffTheRecordProfile()
: Profile.getLastUsedProfile()),
FeedProcessScopeFactory.getFeedLoggingBridge());
return new FeedSurfaceCoordinator(
mActivity, null, null, null, exploreSurfaceActionHandler, isIncognito, this);
// TODO(crbug.com/982018): Customize surface background for incognito and dark mode.
// TODO(crbug.com/982018): Hide signin promo UI in incognito mode.
}
} }
\ No newline at end of file
// Copyright 2019 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.features.start_surface;
import android.content.Context;
import android.net.Uri;
import android.provider.Browser;
import android.support.annotation.Nullable;
import android.support.customtabs.CustomTabsIntent;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.start_surface.R;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.ui.mojom.WindowOpenDisposition;
/** Implementation of the {@link NativePageNavigationDelegate} for the explore surface. */
class ExploreSurfaceNavigationDelegate implements NativePageNavigationDelegate {
private final Context mContext;
private boolean mIsInCognito;
ExploreSurfaceNavigationDelegate(Context context) {
mContext = context;
}
@Override
public boolean isOpenInNewWindowEnabled() {
return false;
}
// TODO(crbug.com/982018): Experiment opening feeds in normal Tabs.
@Override
@Nullable
public Tab openUrl(int windowOpenDisposition, LoadUrlParams loadUrlParams) {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
builder.setShowTitle(true);
builder.setStartAnimations(mContext, R.anim.abc_grow_fade_in_from_bottom, 0);
builder.setExitAnimations(mContext, 0, R.anim.abc_shrink_fade_out_from_bottom);
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.intent.setPackage(mContext.getPackageName());
customTabsIntent.intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB,
(windowOpenDisposition == WindowOpenDisposition.OFF_THE_RECORD || mIsInCognito)
? true
: false);
customTabsIntent.intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName());
customTabsIntent.launchUrl(mContext, Uri.parse(loadUrlParams.getUrl()));
// TODO(crbug.com/982018): Return the opened tab and make sure it is opened in incoginito
// mode accordingly (note that payment window supports incognito mode).
return null;
}
public void setIncognito(boolean isIncognito) {
mIsInCognito = isIncognito;
}
}
\ No newline at end of file
// Copyright 2019 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.features.start_surface;
import android.app.Activity;
import com.google.android.libraries.feed.api.client.stream.Stream;
import org.chromium.chrome.browser.feed.StreamLifecycleManager;
/** Explore surface feed stream lifecycle manager. */
class ExploreSurfaceStreamLifecycleManager extends StreamLifecycleManager {
/**
* The constructor.
* @param stream The {@link Stream} this manager manages.
* @param activity The activity the {@link Stream} associates with.
*/
ExploreSurfaceStreamLifecycleManager(Stream stream, Activity activity) {
super(stream, activity);
start();
}
// TODO(crbug.com/982018): Save and restore instance state when opening the feeds in normal
// Tabs.
}
\ No newline at end of file
// Copyright 2019 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.features.start_surface;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_EXPLORE_SURFACE_VISIBLE;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_INCOGNITO;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import org.chromium.chrome.browser.feed.FeedSurfaceCoordinator;
import org.chromium.ui.UiUtils;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
/** Binder for the explore surface. */
class ExploreSurfaceViewBinder {
/** Interface to access {@link FeedSurfaceCoordinator} */
interface FeedSurfaceDelegate {
/**
* Creates the {@link FeedSurfaceCoordinator} for the specified mode.
* @param isIncognito Whether it is in incognito mode.
* @return The {@link FeedSurfaceCoordinator}.
*/
FeedSurfaceCoordinator createFeedSurfaceCoordinator(boolean isIncognito);
}
/** The class holds all views, their information and status. */
public static class ViewHolder {
public final ViewGroup containerView;
public final int bottomControlsHeight;
public final int topMargin;
public final FeedSurfaceDelegate feedSurfaceDelegate;
// feedSurfaceCoordinator will be rebuilt when incognito state is changed to use the right
// profile and color, and it will be destroyed when overview mode is hiding to release
// resources.
public FeedSurfaceCoordinator feedSurfaceCoordinator;
public boolean isIncognito;
public boolean isShown;
ViewHolder(ViewGroup containerView, int bottomControlsHeight, int topMargin,
FeedSurfaceDelegate feedSurfaceDelegate) {
this.containerView = containerView;
this.bottomControlsHeight = bottomControlsHeight;
this.topMargin = topMargin;
this.feedSurfaceDelegate = feedSurfaceDelegate;
}
}
public static void bind(PropertyModel model, ViewHolder view, PropertyKey propertyKey) {
if (propertyKey == IS_INCOGNITO) {
setIncognito(view, model.get(IS_INCOGNITO));
} else if (propertyKey == IS_EXPLORE_SURFACE_VISIBLE) {
setVisibility(view, model.get(IS_EXPLORE_SURFACE_VISIBLE));
} else if (propertyKey == IS_SHOWING_OVERVIEW) {
// Set the initial state if the explore surface is selected previously.
setOverview(
view, model.get(IS_SHOWING_OVERVIEW), model.get(IS_EXPLORE_SURFACE_VISIBLE));
}
}
private static void setIncognito(ViewHolder viewHolder, boolean isIncognito) {
if (viewHolder.isIncognito == isIncognito) return;
viewHolder.isIncognito = isIncognito;
// Set invisible to remove the view from it's parent if it was showing and destroy the feed
// surface coordinator (no matter it was shown or not).
boolean wasShown = viewHolder.isShown;
if (wasShown) setVisibility(viewHolder, false);
destroy(viewHolder);
// Set visible if it was shown, which will build the new feed surface coordinator according
// to the new incognito state.
if (wasShown) setVisibility(viewHolder, true);
}
/** This interface builds the feed surface coordinator when showing if needed. */
private static void setVisibility(ViewHolder viewHolder, boolean shown) {
if (viewHolder.isShown == shown) return;
if (shown) {
if (viewHolder.feedSurfaceCoordinator == null) {
viewHolder.feedSurfaceCoordinator =
viewHolder.feedSurfaceDelegate.createFeedSurfaceCoordinator(
viewHolder.isIncognito);
}
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
layoutParams.bottomMargin = viewHolder.bottomControlsHeight;
layoutParams.topMargin = viewHolder.topMargin;
viewHolder.containerView.addView(
viewHolder.feedSurfaceCoordinator.getView(), layoutParams);
} else {
if (viewHolder.feedSurfaceCoordinator != null)
UiUtils.removeViewFromParent(viewHolder.feedSurfaceCoordinator.getView());
}
viewHolder.isShown = shown;
}
private static void setOverview(
ViewHolder viewHolder, boolean isShowingOverview, boolean wasExploreSurfaceVisible) {
if (isShowingOverview) {
setVisibility(viewHolder, wasExploreSurfaceVisible);
} else {
setVisibility(viewHolder, false);
destroy(viewHolder);
}
}
private static void destroy(ViewHolder viewHolder) {
if (viewHolder.feedSurfaceCoordinator != null) viewHolder.feedSurfaceCoordinator.destroy();
viewHolder.feedSurfaceCoordinator = null;
}
}
\ No newline at end of file
...@@ -11,7 +11,6 @@ import org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcher; ...@@ -11,7 +11,6 @@ import org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcher;
import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider; import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider;
import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.FeatureUtilities;
import org.chromium.chrome.start_surface.R; import org.chromium.chrome.start_surface.R;
import org.chromium.ui.modelutil.PropertyModel;
/** /**
* Root coordinator that is responsible for showing start surfaces, like a grid of Tabs, explore * Root coordinator that is responsible for showing start surfaces, like a grid of Tabs, explore
...@@ -22,7 +21,6 @@ public class StartSurfaceCoordinator implements StartSurface { ...@@ -22,7 +21,6 @@ public class StartSurfaceCoordinator implements StartSurface {
private final StartSurfaceMediator mStartSurfaceMediator; private final StartSurfaceMediator mStartSurfaceMediator;
private BottomBarCoordinator mBottomBarCoordinator; private BottomBarCoordinator mBottomBarCoordinator;
private ExploreSurfaceCoordinator mExploreSurfaceCoordinator; private ExploreSurfaceCoordinator mExploreSurfaceCoordinator;
private PropertyModel mPropertyModel;
public StartSurfaceCoordinator(ChromeActivity activity) { public StartSurfaceCoordinator(ChromeActivity activity) {
mGridTabSwitcher = mGridTabSwitcher =
...@@ -33,24 +31,20 @@ public class StartSurfaceCoordinator implements StartSurface { ...@@ -33,24 +31,20 @@ public class StartSurfaceCoordinator implements StartSurface {
if (ChromeFeatureList.isEnabled(ChromeFeatureList.TWO_PANES_START_SURFACE_ANDROID) if (ChromeFeatureList.isEnabled(ChromeFeatureList.TWO_PANES_START_SURFACE_ANDROID)
&& !FeatureUtilities.isBottomToolbarEnabled()) { && !FeatureUtilities.isBottomToolbarEnabled()) {
// Margin the bottom of the Tab grid to save space for the bottom bar. // Margin the bottom of the Tab grid to save space for the bottom bar.
int bottomBarHeight = mGridTabSwitcher.getTabGridDelegate().setBottomControlsHeight(
ContextUtils.getApplicationContext().getResources().getDimensionPixelSize( ContextUtils.getApplicationContext().getResources().getDimensionPixelSize(
R.dimen.ss_bottom_bar_height); R.dimen.ss_bottom_bar_height));
mGridTabSwitcher.getTabGridDelegate().setBottomControlsHeight(bottomBarHeight);
mPropertyModel = new PropertyModel(StartSurfaceProperties.ALL_KEYS);
// Create the bottom bar. // Create the bottom bar.
mBottomBarCoordinator = new BottomBarCoordinator( mBottomBarCoordinator = new BottomBarCoordinator(
activity, activity.getCompositorViewHolder(), mPropertyModel); activity, activity.getCompositorViewHolder(), activity.getTabModelSelector());
// Create the explore surface. // Create the explore surface.
mExploreSurfaceCoordinator = new ExploreSurfaceCoordinator( mExploreSurfaceCoordinator = new ExploreSurfaceCoordinator();
activity, activity.getCompositorViewHolder(), bottomBarHeight, mPropertyModel);
} }
mStartSurfaceMediator = new StartSurfaceMediator(mGridTabSwitcher.getGridController(), mStartSurfaceMediator = new StartSurfaceMediator(mGridTabSwitcher.getGridController(),
mPropertyModel, activity.getTabModelSelector()); mBottomBarCoordinator, mExploreSurfaceCoordinator);
} }
// Implements StartSurface. // Implements StartSurface.
......
...@@ -4,19 +4,10 @@ ...@@ -4,19 +4,10 @@
package org.chromium.chrome.features.start_surface; package org.chromium.chrome.features.start_surface;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.BottomBarClickListener;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_EXPLORE_SURFACE_VISIBLE;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_INCOGNITO;
import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.chromium.base.ObserverList; import org.chromium.base.ObserverList;
import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcher; import org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcher;
import org.chromium.ui.modelutil.PropertyModel;
/** The mediator implements the logic to interact with the surfaces and caller. */ /** The mediator implements the logic to interact with the surfaces and caller. */
class StartSurfaceMediator class StartSurfaceMediator
...@@ -24,42 +15,30 @@ class StartSurfaceMediator ...@@ -24,42 +15,30 @@ class StartSurfaceMediator
private final ObserverList<StartSurface.OverviewModeObserver> mObservers = new ObserverList<>(); private final ObserverList<StartSurface.OverviewModeObserver> mObservers = new ObserverList<>();
private final GridTabSwitcher.GridController mGridController; private final GridTabSwitcher.GridController mGridController;
@Nullable @Nullable
private final PropertyModel mPropertyModel; private final BottomBarCoordinator mBottomBarCoordinator;
@Nullable
private final ExploreSurfaceCoordinator mExploreSurfaceCoordinator;
StartSurfaceMediator(GridTabSwitcher.GridController gridController, StartSurfaceMediator(GridTabSwitcher.GridController gridController,
@Nullable PropertyModel propertyModel, TabModelSelector tabModelSelector) { @Nullable BottomBarCoordinator bottomBarCoordinator,
@Nullable ExploreSurfaceCoordinator exploreSurfaceCoordinator) {
mGridController = gridController; mGridController = gridController;
mPropertyModel = propertyModel; mBottomBarCoordinator = bottomBarCoordinator;
mExploreSurfaceCoordinator = exploreSurfaceCoordinator;
if (mPropertyModel != null) {
mPropertyModel.set( if (mBottomBarCoordinator != null) {
BottomBarClickListener, new StartSurfaceProperties.BottomBarClickListener() { mBottomBarCoordinator.setOnClickListener(new BottomBarProperties.OnClickListener() {
// TODO(crbug.com/982018): Animate switching between explore and home
// surface.
@Override
public void onHomeButtonClicked() {
mPropertyModel.set(IS_EXPLORE_SURFACE_VISIBLE, false);
}
@Override
public void onExploreButtonClicked() {
// TODO(crbug.com/982018): Hide the Tab switcher toolbar when showing
// explore surface.
mPropertyModel.set(IS_EXPLORE_SURFACE_VISIBLE, true);
}
});
tabModelSelector.addObserver(new EmptyTabModelSelectorObserver() {
@Override @Override
public void onTabModelSelected(TabModel newModel, TabModel oldModel) { public void onHomeButtonClicked() {
mPropertyModel.set(IS_INCOGNITO, newModel.isIncognito()); // TODO(crbug.com/982018): Show home surface and hide explore surface.
} }
});
// Set the initial state. @Override
mPropertyModel.set(IS_INCOGNITO, tabModelSelector.isIncognitoSelected()); public void onExploreButtonClicked() {
// TODO(crbug.com/982018): Show explore surface and hide home surface.
}
});
} }
mGridController.addOverviewModeObserver(this); mGridController.addOverviewModeObserver(this);
} }
...@@ -89,7 +68,7 @@ class StartSurfaceMediator ...@@ -89,7 +68,7 @@ class StartSurfaceMediator
mGridController.showOverview(animate); mGridController.showOverview(animate);
// TODO(crbug.com/982018): Animate the bottom bar together with the Tab Grid view. // TODO(crbug.com/982018): Animate the bottom bar together with the Tab Grid view.
if (mPropertyModel != null) mPropertyModel.set(IS_SHOWING_OVERVIEW, true); if (mBottomBarCoordinator != null) mBottomBarCoordinator.setVisibility(true);
} }
@Override @Override
...@@ -116,7 +95,7 @@ class StartSurfaceMediator ...@@ -116,7 +95,7 @@ class StartSurfaceMediator
@Override @Override
public void startedHiding() { public void startedHiding() {
if (mPropertyModel != null) mPropertyModel.set(IS_SHOWING_OVERVIEW, false); if (mBottomBarCoordinator != null) mBottomBarCoordinator.setVisibility(false);
for (StartSurface.OverviewModeObserver observer : mObservers) { for (StartSurface.OverviewModeObserver observer : mObservers) {
observer.startedHiding(); observer.startedHiding();
} }
......
...@@ -26,23 +26,22 @@ import org.chromium.chrome.browser.ntp.snippets.SectionHeader; ...@@ -26,23 +26,22 @@ import org.chromium.chrome.browser.ntp.snippets.SectionHeader;
import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.preferences.PrefChangeRegistrar; import org.chromium.chrome.browser.preferences.PrefChangeRegistrar;
import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.signin.IdentityServicesProvider;
import org.chromium.chrome.browser.signin.PersonalizedSigninPromoView; import org.chromium.chrome.browser.signin.PersonalizedSigninPromoView;
import org.chromium.chrome.browser.signin.SigninManager; import org.chromium.chrome.browser.signin.SigninManager;
import org.chromium.chrome.browser.signin.SigninPromoUtil; import org.chromium.chrome.browser.signin.SigninPromoUtil;
/** /**
* A mediator for the {@link FeedSurfaceCoordinator} responsible for interacting with the * A mediator for the {@link FeedNewTabPage} responsible for interacting with the
* native library and handling business logic. * native library and handling business logic.
*/ */
class FeedSurfaceMediator class FeedNewTabPageMediator
implements NewTabPageLayout.ScrollDelegate, ContextMenuManager.TouchEnabledDelegate { implements NewTabPageLayout.ScrollDelegate, ContextMenuManager.TouchEnabledDelegate {
private final FeedSurfaceCoordinator mCoordinator; private final FeedNewTabPage mCoordinator;
private final @Nullable SnapScrollHelper mSnapScrollHelper; private final SnapScrollHelper mSnapScrollHelper;
private final PrefChangeRegistrar mPrefChangeRegistrar; private final PrefChangeRegistrar mPrefChangeRegistrar;
private final SigninManager mSigninManager; private final SigninManager mSigninManager;
private @Nullable ScrollListener mStreamScrollListener; private ScrollListener mStreamScrollListener;
private ContentChangedListener mStreamContentChangedListener; private ContentChangedListener mStreamContentChangedListener;
private SectionHeader mSectionHeader; private SectionHeader mSectionHeader;
private MemoryPressureCallback mMemoryPressureCallback; private MemoryPressureCallback mMemoryPressureCallback;
...@@ -56,14 +55,14 @@ class FeedSurfaceMediator ...@@ -56,14 +55,14 @@ class FeedSurfaceMediator
private int mThumbnailScrollY; private int mThumbnailScrollY;
/** /**
* @param coordinator The {@link FeedSurfaceCoordinator} that interacts with this class. * @param feedNewTabPage The {@link FeedNewTabPage} that interacts with this class.
* @param snapScrollHelper The {@link SnapScrollHelper} that handles snap scrolling. * @param snapScrollHelper The {@link SnapScrollHelper} that handles snap scrolling.
*/ */
FeedSurfaceMediator( FeedNewTabPageMediator(FeedNewTabPage feedNewTabPage, SnapScrollHelper snapScrollHelper,
FeedSurfaceCoordinator coordinator, @Nullable SnapScrollHelper snapScrollHelper) { SigninManager signinManager) {
mCoordinator = coordinator; mCoordinator = feedNewTabPage;
mSnapScrollHelper = snapScrollHelper; mSnapScrollHelper = snapScrollHelper;
mSigninManager = IdentityServicesProvider.getSigninManager(); mSigninManager = signinManager;
mPrefChangeRegistrar = new PrefChangeRegistrar(); mPrefChangeRegistrar = new PrefChangeRegistrar();
mPrefChangeRegistrar.addObserver(Pref.NTP_ARTICLES_SECTION_ENABLED, this::updateContent); mPrefChangeRegistrar.addObserver(Pref.NTP_ARTICLES_SECTION_ENABLED, this::updateContent);
...@@ -79,8 +78,6 @@ class FeedSurfaceMediator ...@@ -79,8 +78,6 @@ class FeedSurfaceMediator
} }
private void initialize() { private void initialize() {
if (mSnapScrollHelper == null) return;
// Listen for layout changes on the NewTabPageView itself to catch changes in scroll // Listen for layout changes on the NewTabPageView itself to catch changes in scroll
// position that are due to layout changes after e.g. device rotation. This contrasts with // position that are due to layout changes after e.g. device rotation. This contrasts with
// regular scrolling, which is observed through an OnScrollListener. // regular scrolling, which is observed through an OnScrollListener.
...@@ -99,14 +96,12 @@ class FeedSurfaceMediator ...@@ -99,14 +96,12 @@ class FeedSurfaceMediator
if (mFeedEnabled) { if (mFeedEnabled) {
mCoordinator.createStream(); mCoordinator.createStream();
if (mSnapScrollHelper != null) mSnapScrollHelper.setView(mCoordinator.getStream().getView());
mSnapScrollHelper.setView(mCoordinator.getStream().getView());
initializePropertiesForStream(); initializePropertiesForStream();
} else { } else {
destroyPropertiesForStream(); destroyPropertiesForStream();
mCoordinator.createScrollViewForPolicy(); mCoordinator.createScrollViewForPolicy();
if (mSnapScrollHelper != null) mSnapScrollHelper.setView(mCoordinator.getScrollViewForPolicy());
mSnapScrollHelper.setView(mCoordinator.getScrollViewForPolicy());
initializePropertiesForPolicy(); initializePropertiesForPolicy();
} }
} }
...@@ -117,23 +112,20 @@ class FeedSurfaceMediator ...@@ -117,23 +112,20 @@ class FeedSurfaceMediator
*/ */
private void initializePropertiesForStream() { private void initializePropertiesForStream() {
Stream stream = mCoordinator.getStream(); Stream stream = mCoordinator.getStream();
mStreamScrollListener = new ScrollListener() {
if (mSnapScrollHelper != null) { @Override
mStreamScrollListener = new ScrollListener() { public void onScrollStateChanged(int state) {}
@Override
public void onScrollStateChanged(int state) {} @Override
public void onScrolled(int dx, int dy) {
@Override mSnapScrollHelper.handleScroll();
public void onScrolled(int dx, int dy) { }
mSnapScrollHelper.handleScroll(); };
} stream.addScrollListener(mStreamScrollListener);
};
stream.addScrollListener(mStreamScrollListener);
}
mStreamContentChangedListener = () -> { mStreamContentChangedListener = () -> {
mStreamContentChanged = true; mStreamContentChanged = true;
if (mSnapScrollHelper != null) mSnapScrollHelper.resetSearchBoxOnScroll(true); mSnapScrollHelper.resetSearchBoxOnScroll(true);
}; };
stream.addOnContentChangedListener(mStreamContentChangedListener); stream.addOnContentChangedListener(mStreamContentChangedListener);
...@@ -163,10 +155,8 @@ class FeedSurfaceMediator ...@@ -163,10 +155,8 @@ class FeedSurfaceMediator
Stream stream = mCoordinator.getStream(); Stream stream = mCoordinator.getStream();
if (stream == null) return; if (stream == null) return;
if (mStreamScrollListener != null) { stream.removeScrollListener(mStreamScrollListener);
stream.removeScrollListener(mStreamScrollListener); mStreamScrollListener = null;
mStreamScrollListener = null;
}
stream.removeOnContentChangedListener(mStreamContentChangedListener); stream.removeOnContentChangedListener(mStreamContentChangedListener);
mStreamContentChangedListener = null; mStreamContentChangedListener = null;
...@@ -187,9 +177,7 @@ class FeedSurfaceMediator ...@@ -187,9 +177,7 @@ class FeedSurfaceMediator
*/ */
private void initializePropertiesForPolicy() { private void initializePropertiesForPolicy() {
ScrollView view = mCoordinator.getScrollViewForPolicy(); ScrollView view = mCoordinator.getScrollViewForPolicy();
if (mSnapScrollHelper != null) { view.getViewTreeObserver().addOnScrollChangedListener(mSnapScrollHelper::handleScroll);
view.getViewTreeObserver().addOnScrollChangedListener(mSnapScrollHelper::handleScroll);
}
} }
/** Update whether the section header should be expanded. */ /** Update whether the section header should be expanded. */
...@@ -301,7 +289,6 @@ class FeedSurfaceMediator ...@@ -301,7 +289,6 @@ class FeedSurfaceMediator
@Override @Override
public void snapScroll() { public void snapScroll() {
if (mSnapScrollHelper == null) return;
if (!isScrollViewInitialized()) return; if (!isScrollViewInitialized()) return;
int initialScroll = getVerticalScrollOffset(); int initialScroll = getVerticalScrollOffset();
......
...@@ -71,19 +71,6 @@ public class FeedProcessScopeFactory { ...@@ -71,19 +71,6 @@ public class FeedProcessScopeFactory {
return sFeedScheduler; return sFeedScheduler;
} }
/**
* @return The {@link Runnable} to notify feed has been consumed.
*/
public static Runnable getFeedConsumptionObserver() {
Runnable consumptionObserver = () -> {
FeedScheduler scheduler = getFeedScheduler();
if (scheduler != null) {
scheduler.onSuggestionConsumed();
}
};
return consumptionObserver;
}
/** /**
* @return The {@link FeedOfflineIndicator} that was given to the {@link ProcessScope}. * @return The {@link FeedOfflineIndicator} that was given to the {@link ProcessScope}.
* Null if the Feed is disabled. * Null if the Feed is disabled.
......
// Copyright 2018 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;
import android.app.Activity;
import com.google.android.libraries.feed.api.client.stream.Stream;
import com.sun.istack.internal.Nullable;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.ntp.NewTabPage;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.Tab.TabHidingType;
import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.chrome.browser.tabmodel.TabSelectionType;
import org.chromium.content_public.browser.NavigationController;
import org.chromium.content_public.browser.NavigationEntry;
/**
* Manages the lifecycle of a {@link Stream} associated with a Tab in an Activity.
*/
final class NtpStreamLifecycleManager extends StreamLifecycleManager {
/** Key for the Stream instance state that may be stored in a navigation entry. */
private static final String STREAM_SAVED_INSTANCE_STATE_KEY = "StreamSavedInstanceState";
/** The {@link Tab} that {@link #mStream} is attached to. */
private final Tab mTab;
/**
* The {@link TabObserver} that observes tab state changes and notifies the {@link Stream}
* accordingly.
*/
private final TabObserver mTabObserver;
/**
* @param stream The {@link Stream} that this class manages.
* @param activity The {@link Activity} that the {@link Stream} is attached to.
* @param tab The {@link Tab} that the {@link Stream} is attached to.
*/
NtpStreamLifecycleManager(Stream stream, Activity activity, Tab tab) {
super(stream, activity);
// Set mTab before 'start' since 'restoreInstanceState' will use it.
mTab = tab;
start();
// We don't need to handle mStream#onDestroy here since this class will be destroyed when
// the associated FeedNewTabPage is destroyed.
mTabObserver = new EmptyTabObserver() {
@Override
public void onInteractabilityChanged(boolean isInteractable) {
if (isInteractable) {
activate();
} else {
deactivate();
}
}
@Override
public void onShown(Tab tab, @TabSelectionType int type) {
show();
}
@Override
public void onHidden(Tab tab, @TabHidingType int type) {
hide();
}
@Override
public void onPageLoadStarted(Tab tab, String url) {
saveInstanceState();
}
};
mTab.addObserver(mTabObserver);
}
/** @return Whether the {@link Stream} can be shown. */
@Override
protected boolean canShow() {
return super.canShow() && !mTab.isHidden();
}
/** @return Whether the {@link Stream} can be activated. */
@Override
protected boolean canActivate() {
return super.canActivate() && mTab.isUserInteractable();
}
/**
* Clears any dependencies and calls {@link Stream#onDestroy()} when this class is not needed
* anymore.
*/
@Override
protected void destroy() {
if (mStreamState == StreamState.DESTROYED) return;
super.destroy();
mTab.removeObserver(mTabObserver);
}
/** Save the Stream instance state to the navigation entry if necessary. */
@Override
protected void saveInstanceState() {
if (mTab.getWebContents() == null) return;
NavigationController controller = mTab.getWebContents().getNavigationController();
int index = controller.getLastCommittedEntryIndex();
NavigationEntry entry = controller.getEntryAtIndex(index);
if (entry == null) return;
// At least under test conditions this method may be called initially for the load of the
// NTP itself, at which point the last committed entry is not for the NTP yet. This method
// will then be called a second time when the user navigates away, at which point the last
// committed entry is for the NTP. The extra data must only be set in the latter case.
if (!NewTabPage.isNTPUrl(entry.getUrl())) return;
controller.setEntryExtraData(
index, STREAM_SAVED_INSTANCE_STATE_KEY, mStream.getSavedInstanceStateString());
}
/**
* @return The Stream instance state saved in navigation entry, or null if it is not previously
* saved.
*/
@Override
@Nullable
protected String restoreInstanceState() {
if (mTab.getWebContents() == null) return null;
NavigationController controller = mTab.getWebContents().getNavigationController();
int index = controller.getLastCommittedEntryIndex();
return controller.getEntryExtraData(index, STREAM_SAVED_INSTANCE_STATE_KEY);
}
@VisibleForTesting
TabObserver getTabObserverForTesting() {
return mTabObserver;
}
}
...@@ -8,23 +8,31 @@ import android.app.Activity; ...@@ -8,23 +8,31 @@ import android.app.Activity;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import com.google.android.libraries.feed.api.client.stream.Stream; import com.google.android.libraries.feed.api.client.stream.Stream;
import com.sun.istack.internal.Nullable;
import org.chromium.base.ActivityState; import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus; import org.chromium.base.ApplicationStatus;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.ntp.NewTabPage;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.Tab.TabHidingType;
import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.chrome.browser.tabmodel.TabSelectionType;
import org.chromium.content_public.browser.NavigationController;
import org.chromium.content_public.browser.NavigationEntry;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
/** /**
* Manages the lifecycle of a {@link Stream} associated with an Activity. * Manages the lifecycle of a {@link Stream}.
*/ */
public class StreamLifecycleManager implements ApplicationStatus.ActivityStateListener { class StreamLifecycleManager implements ApplicationStatus.ActivityStateListener {
/** The different states that the Stream can be in its lifecycle. */ /** The different states that the Stream can be in its lifecycle. */
@IntDef({StreamState.NOT_SPECIFIED, StreamState.CREATED, StreamState.SHOWN, StreamState.ACTIVE, @IntDef({StreamState.NOT_SPECIFIED, StreamState.CREATED, StreamState.SHOWN, StreamState.ACTIVE,
StreamState.INACTIVE, StreamState.HIDDEN, StreamState.DESTROYED}) StreamState.INACTIVE, StreamState.HIDDEN, StreamState.DESTROYED})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
protected @interface StreamState { private @interface StreamState {
int NOT_SPECIFIED = -1; int NOT_SPECIFIED = -1;
int CREATED = 0; int CREATED = 0;
int SHOWN = 1; int SHOWN = 1;
...@@ -34,30 +42,71 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi ...@@ -34,30 +42,71 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi
int DESTROYED = 5; int DESTROYED = 5;
} }
/** The {@link Stream} that this class manages. */ /** Key for the Stream instance state that may be stored in a navigation entry. */
protected final Stream mStream; private static final String STREAM_SAVED_INSTANCE_STATE_KEY = "StreamSavedInstanceState";
/** The current state the Stream is in its lifecycle. */ /** The {@link Stream} that this class manages. */
protected @StreamState int mStreamState = StreamState.NOT_SPECIFIED; private final Stream mStream;
/** The {@link Activity} that {@link #mStream} is attached to. */ /** The {@link Activity} that {@link #mStream} is attached to. */
private final Activity mActivity; private final Activity mActivity;
/** The {@link Tab} that {@link #mStream} is attached to. */
private final Tab mTab;
/**
* The {@link TabObserver} that observes tab state changes and notifies the {@link Stream}
* accordingly.
*/
private final TabObserver mTabObserver;
/** The current state the Stream is in its lifecycle. */
private @StreamState int mStreamState = StreamState.NOT_SPECIFIED;
/** /**
* @param stream The {@link Stream} that this class manages. * @param stream The {@link Stream} that this class manages.
* @param activity The {@link Activity} that the {@link Stream} is attached to. * @param activity The {@link Activity} that the {@link Stream} is attached to.
* @param tab The {@link Tab} that the {@link Stream} is attached to.
*/ */
public StreamLifecycleManager(Stream stream, Activity activity) { StreamLifecycleManager(Stream stream, Activity activity, Tab tab) {
mStream = stream; mStream = stream;
mActivity = activity; mActivity = activity;
} mTab = tab;
// We don't need to handle mStream#onDestroy here since this class will be destroyed when
// the associated FeedNewTabPage is destroyed.
mTabObserver = new EmptyTabObserver() {
@Override
public void onInteractabilityChanged(boolean isInteractable) {
if (isInteractable) {
activate();
} else {
deactivate();
}
}
@Override
public void onShown(Tab tab, @TabSelectionType int type) {
show();
}
@Override
public void onHidden(Tab tab, @TabHidingType int type) {
hide();
}
@Override
public void onPageLoadStarted(Tab tab, String url) {
saveInstanceState();
}
};
protected void start() {
mStreamState = StreamState.CREATED; mStreamState = StreamState.CREATED;
mStream.onCreate(restoreInstanceState()); mStream.onCreate(restoreInstanceState());
show(); show();
activate(); activate();
mTab.addObserver(mTabObserver);
ApplicationStatus.registerStateListenerForActivity(this, mActivity); ApplicationStatus.registerStateListenerForActivity(this, mActivity);
} }
...@@ -86,17 +135,18 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi ...@@ -86,17 +135,18 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi
} }
/** @return Whether the {@link Stream} can be shown. */ /** @return Whether the {@link Stream} can be shown. */
protected boolean canShow() { private boolean canShow() {
final int state = ApplicationStatus.getStateForActivity(mActivity); final int state = ApplicationStatus.getStateForActivity(mActivity);
// We don't call Stream#onShow to prevent feed services from being warmed up if the user // We don't call Stream#onShow to prevent feed services from being warmed up if the user
// has opted out from article suggestions during the previous session. // has opted out from article suggestions during the previous session.
return (mStreamState == StreamState.CREATED || mStreamState == StreamState.HIDDEN) return (mStreamState == StreamState.CREATED || mStreamState == StreamState.HIDDEN)
&& !mTab.isHidden()
&& (state == ActivityState.STARTED || state == ActivityState.RESUMED) && (state == ActivityState.STARTED || state == ActivityState.RESUMED)
&& FeedProcessScopeFactory.areArticlesVisibleDuringSession(); && FeedProcessScopeFactory.areArticlesVisibleDuringSession();
} }
/** Calls {@link Stream#onShow()}. */ /** Calls {@link Stream#onShow()}. */
protected void show() { private void show() {
if (!canShow()) return; if (!canShow()) return;
mStreamState = StreamState.SHOWN; mStreamState = StreamState.SHOWN;
...@@ -104,14 +154,15 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi ...@@ -104,14 +154,15 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi
} }
/** @return Whether the {@link Stream} can be activated. */ /** @return Whether the {@link Stream} can be activated. */
protected boolean canActivate() { private boolean canActivate() {
return (mStreamState == StreamState.SHOWN || mStreamState == StreamState.INACTIVE) return (mStreamState == StreamState.SHOWN || mStreamState == StreamState.INACTIVE)
&& mTab.isUserInteractable()
&& ApplicationStatus.getStateForActivity(mActivity) == ActivityState.RESUMED && ApplicationStatus.getStateForActivity(mActivity) == ActivityState.RESUMED
&& FeedProcessScopeFactory.areArticlesVisibleDuringSession(); && FeedProcessScopeFactory.areArticlesVisibleDuringSession();
} }
/** Calls {@link Stream#onActive()}. */ /** Calls {@link Stream#onActive()}. */
protected void activate() { void activate() {
// Make sure the Stream can be shown and is set shown before setting it to active state. // Make sure the Stream can be shown and is set shown before setting it to active state.
show(); show();
if (!canActivate()) return; if (!canActivate()) return;
...@@ -121,7 +172,7 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi ...@@ -121,7 +172,7 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi
} }
/** Calls {@link Stream#onInactive()}. */ /** Calls {@link Stream#onInactive()}. */
protected void deactivate() { private void deactivate() {
if (mStreamState != StreamState.ACTIVE) return; if (mStreamState != StreamState.ACTIVE) return;
mStreamState = StreamState.INACTIVE; mStreamState = StreamState.INACTIVE;
...@@ -129,7 +180,7 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi ...@@ -129,7 +180,7 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi
} }
/** Calls {@link Stream#onHide()}. */ /** Calls {@link Stream#onHide()}. */
protected void hide() { private void hide() {
if (mStreamState == StreamState.HIDDEN || mStreamState == StreamState.CREATED if (mStreamState == StreamState.HIDDEN || mStreamState == StreamState.CREATED
|| mStreamState == StreamState.DESTROYED) || mStreamState == StreamState.DESTROYED)
return; return;
...@@ -147,25 +198,50 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi ...@@ -147,25 +198,50 @@ public class StreamLifecycleManager implements ApplicationStatus.ActivityStateLi
* Clears any dependencies and calls {@link Stream#onDestroy()} when this class is not needed * Clears any dependencies and calls {@link Stream#onDestroy()} when this class is not needed
* anymore. * anymore.
*/ */
protected void destroy() { void destroy() {
if (mStreamState == StreamState.DESTROYED) return; if (mStreamState == StreamState.DESTROYED) return;
// Make sure the Stream is hidden before setting it to destroyed state. // Make sure the Stream is hidden before setting it to destroyed state.
hide(); hide();
mStreamState = StreamState.DESTROYED; mStreamState = StreamState.DESTROYED;
mTab.removeObserver(mTabObserver);
ApplicationStatus.unregisterActivityStateListener(this); ApplicationStatus.unregisterActivityStateListener(this);
mStream.onDestroy(); mStream.onDestroy();
} }
/** Save the Stream instance state if necessary. */ /** Save the Stream instance state to the navigation entry if necessary. */
protected void saveInstanceState() {} private void saveInstanceState() {
if (mTab.getWebContents() == null) return;
NavigationController controller = mTab.getWebContents().getNavigationController();
int index = controller.getLastCommittedEntryIndex();
NavigationEntry entry = controller.getEntryAtIndex(index);
if (entry == null) return;
// At least under test conditions this method may be called initially for the load of the
// NTP itself, at which point the last committed entry is not for the NTP yet. This method
// will then be called a second time when the user navigates away, at which point the last
// committed entry is for the NTP. The extra data must only be set in the latter case.
if (!NewTabPage.isNTPUrl(entry.getUrl())) return;
controller.setEntryExtraData(
index, STREAM_SAVED_INSTANCE_STATE_KEY, mStream.getSavedInstanceStateString());
}
/** /**
* @return The saved Stream instance state, or null if it is not previously * @return The Stream instance state saved in navigation entry, or null if it is not previously
* saved. * saved.
*/ */
@Nullable private String restoreInstanceState() {
protected String restoreInstanceState() { if (mTab.getWebContents() == null) return null;
return null;
NavigationController controller = mTab.getWebContents().getNavigationController();
int index = controller.getLastCommittedEntryIndex();
return controller.getEntryExtraData(index, STREAM_SAVED_INSTANCE_STATE_KEY);
}
@VisibleForTesting
TabObserver getTabObserverForTesting() {
return mTabObserver;
} }
} }
\ No newline at end of file
...@@ -12,11 +12,11 @@ import com.google.android.libraries.feed.api.host.action.ActionApi; ...@@ -12,11 +12,11 @@ import com.google.android.libraries.feed.api.host.action.ActionApi;
import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.feed.FeedLoggingBridge; import org.chromium.chrome.browser.feed.FeedLoggingBridge;
import org.chromium.chrome.browser.feed.FeedOfflineIndicator; import org.chromium.chrome.browser.feed.FeedOfflineIndicator;
import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate;
import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.ntp.NewTabPage;
import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
import org.chromium.chrome.browser.suggestions.NavigationRecorder; import org.chromium.chrome.browser.suggestions.NavigationRecorder;
import org.chromium.chrome.browser.suggestions.SuggestionsConfig; import org.chromium.chrome.browser.suggestions.SuggestionsConfig;
import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.components.offline_items_collection.LaunchLocation; import org.chromium.components.offline_items_collection.LaunchLocation;
import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.LoadUrlParams;
...@@ -29,14 +29,14 @@ import org.chromium.ui.mojom.WindowOpenDisposition; ...@@ -29,14 +29,14 @@ import org.chromium.ui.mojom.WindowOpenDisposition;
* Handles the actions user can trigger on the feed. * Handles the actions user can trigger on the feed.
*/ */
public class FeedActionHandler implements ActionApi { public class FeedActionHandler implements ActionApi {
private final NativePageNavigationDelegate mDelegate; private final SuggestionsNavigationDelegate mDelegate;
private final Runnable mSuggestionConsumedObserver; private final Runnable mSuggestionConsumedObserver;
private final FeedOfflineIndicator mOfflineIndicator; private final FeedOfflineIndicator mOfflineIndicator;
private final OfflinePageBridge mOfflinePageBridge; private final OfflinePageBridge mOfflinePageBridge;
private final FeedLoggingBridge mLoggingBridge; private final FeedLoggingBridge mLoggingBridge;
/** /**
* @param delegate The {@link NativePageNavigationDelegate} that this handler calls when * @param delegate The {@link SuggestionsNavigationDelegate} that this handler calls when
* handling some of the actions. * handling some of the actions.
* @param suggestionConsumedObserver An observer that is interested in any time a suggestion is * @param suggestionConsumedObserver An observer that is interested in any time a suggestion is
* consumed by the user. * consumed by the user.
...@@ -44,7 +44,7 @@ public class FeedActionHandler implements ActionApi { ...@@ -44,7 +44,7 @@ public class FeedActionHandler implements ActionApi {
* @param offlinePageBridge Capable of updating {@link LoadUrlParams} to include offline ids. * @param offlinePageBridge Capable of updating {@link LoadUrlParams} to include offline ids.
* @param loggingBridge Reports pages visiting time. * @param loggingBridge Reports pages visiting time.
*/ */
public FeedActionHandler(@NonNull NativePageNavigationDelegate delegate, public FeedActionHandler(@NonNull SuggestionsNavigationDelegate delegate,
@NonNull Runnable suggestionConsumedObserver, @NonNull Runnable suggestionConsumedObserver,
@NonNull FeedOfflineIndicator offlineIndicator, @NonNull FeedOfflineIndicator offlineIndicator,
@NonNull OfflinePageBridge offlinePageBridge, @NonNull OfflinePageBridge offlinePageBridge,
......
include_rules = [ include_rules = [
"-components/feed", "-components/feed",
"-third_party/feed", "-third_party/feed"
"+chrome/lib/lifecycle/public"
] ]
...@@ -5,11 +5,10 @@ ...@@ -5,11 +5,10 @@
package org.chromium.chrome.browser.feed; package org.chromium.chrome.browser.feed;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.native_page.NativePageHost; import org.chromium.chrome.browser.native_page.NativePageHost;
import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.ntp.NewTabPage;
import org.chromium.chrome.browser.signin.SigninManager;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
/** /**
...@@ -21,14 +20,10 @@ public class FeedNewTabPage extends NewTabPage { ...@@ -21,14 +20,10 @@ public class FeedNewTabPage extends NewTabPage {
* @param activity The containing {@link ChromeActivity}. * @param activity The containing {@link ChromeActivity}.
* @param nativePageHost The host for this native page. * @param nativePageHost The host for this native page.
* @param tabModelSelector The {@link TabModelSelector} for the containing activity. * @param tabModelSelector The {@link TabModelSelector} for the containing activity.
* @param activityTabProvider Allows us to check if we are the current tab.
* @param activityLifecycleDispatcher Allows us to subscribe to backgrounding events.
*/ */
public FeedNewTabPage(ChromeActivity activity, NativePageHost nativePageHost, public FeedNewTabPage(ChromeActivity activity, NativePageHost nativePageHost,
TabModelSelector tabModelSelector, ActivityTabProvider activityTabProvider, TabModelSelector tabModelSelector, SigninManager signinManager) {
ActivityLifecycleDispatcher activityLifecycleDispatcher) { super(activity, nativePageHost, tabModelSelector);
super(activity, nativePageHost, tabModelSelector, activityTabProvider,
activityLifecycleDispatcher);
} }
@VisibleForTesting @VisibleForTesting
......
...@@ -22,15 +22,13 @@ if (enable_feed_in_chrome) { ...@@ -22,15 +22,13 @@ if (enable_feed_in_chrome) {
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNetworkBridge.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNetworkBridge.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedDebuggingBridge.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedDebuggingBridge.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPageMediator.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedOfflineIndicator.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedOfflineIndicator.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedOfflineBridge.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedOfflineBridge.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedRefreshTask.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedRefreshTask.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManager.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestNetworkClient.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestNetworkClient.java",
"//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/action/FeedActionHandler.java", "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/action/FeedActionHandler.java",
...@@ -47,7 +45,7 @@ if (enable_feed_in_chrome) { ...@@ -47,7 +45,7 @@ if (enable_feed_in_chrome) {
"junit/src/org/chromium/chrome/browser/feed/FeedImageLoaderTest.java", "junit/src/org/chromium/chrome/browser/feed/FeedImageLoaderTest.java",
"junit/src/org/chromium/chrome/browser/feed/FeedJournalStorageTest.java", "junit/src/org/chromium/chrome/browser/feed/FeedJournalStorageTest.java",
"junit/src/org/chromium/chrome/browser/feed/FeedOfflineBridgeTest.java", "junit/src/org/chromium/chrome/browser/feed/FeedOfflineBridgeTest.java",
"junit/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManagerTest.java", "junit/src/org/chromium/chrome/browser/feed/StreamLifecycleManagerTest.java",
"junit/src/org/chromium/chrome/browser/feed/action/FeedActionHandlerTest.java", "junit/src/org/chromium/chrome/browser/feed/action/FeedActionHandlerTest.java",
] ]
......
...@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.ntp.IncognitoNewTabPage; ...@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.ntp.IncognitoNewTabPage;
import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.ntp.NewTabPage;
import org.chromium.chrome.browser.ntp.RecentTabsManager; import org.chromium.chrome.browser.ntp.RecentTabsManager;
import org.chromium.chrome.browser.ntp.RecentTabsPage; import org.chromium.chrome.browser.ntp.RecentTabsPage;
import org.chromium.chrome.browser.signin.IdentityServicesProvider;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
...@@ -58,7 +59,8 @@ public class NativePageFactory { ...@@ -58,7 +59,8 @@ public class NativePageFactory {
if (ChromeFeatureList.isEnabled(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS)) { if (ChromeFeatureList.isEnabled(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS)) {
return new FeedNewTabPage(activity, new TabShim(tab), tabModelSelector, return new FeedNewTabPage(activity, new TabShim(tab), tabModelSelector,
activityTabProvider, activityLifecycleDispatcher); IdentityServicesProvider.getSigninManager(), activityTabProvider,
activityLifecycleDispatcher);
} }
return new NewTabPage(activity, new TabShim(tab), tabModelSelector, activityTabProvider, return new NewTabPage(activity, new TabShim(tab), tabModelSelector, activityTabProvider,
......
...@@ -117,8 +117,7 @@ public class FeedNewTabPageTest { ...@@ -117,8 +117,7 @@ public class FeedNewTabPageTest {
SignInPromo.SigninObserver signinObserver = mNtp.getMediatorForTesting() SignInPromo.SigninObserver signinObserver = mNtp.getMediatorForTesting()
.getSignInPromoForTesting() .getSignInPromoForTesting()
.getSigninObserverForTesting(); .getSigninObserverForTesting();
RecyclerView recyclerView = RecyclerView recyclerView = (RecyclerView) mNtp.getStream().getView();
(RecyclerView) mNtp.getCoordinatorForTesting().getStream().getView();
// Prioritize RecyclerView's focusability so that the sign-in promo button and the action // Prioritize RecyclerView's focusability so that the sign-in promo button and the action
// button don't get focused initially to avoid flakiness. // button don't get focused initially to avoid flakiness.
...@@ -178,7 +177,7 @@ public class FeedNewTabPageTest { ...@@ -178,7 +177,7 @@ public class FeedNewTabPageTest {
.perform(RecyclerViewActions.actionOnItemAtPosition( .perform(RecyclerViewActions.actionOnItemAtPosition(
SIGNIN_PROMO_POSITION, swipeLeft())); SIGNIN_PROMO_POSITION, swipeLeft()));
ViewGroup view = (ViewGroup) mNtp.getCoordinatorForTesting().getStream().getView(); ViewGroup view = (ViewGroup) mNtp.getStream().getView();
waitForView(view, withId(R.id.signin_promo_view_container), VIEW_NULL); waitForView(view, withId(R.id.signin_promo_view_container), VIEW_NULL);
waitForView(view, allOf(withId(R.id.header_title), isDisplayed())); waitForView(view, allOf(withId(R.id.header_title), isDisplayed()));
...@@ -204,8 +203,7 @@ public class FeedNewTabPageTest { ...@@ -204,8 +203,7 @@ public class FeedNewTabPageTest {
Tab tab1 = mActivityTestRule.loadUrlInNewTab(UrlConstants.NTP_URL); Tab tab1 = mActivityTestRule.loadUrlInNewTab(UrlConstants.NTP_URL);
FeedNewTabPage ntp1 = (FeedNewTabPage) tab1.getNativePage(); FeedNewTabPage ntp1 = (FeedNewTabPage) tab1.getNativePage();
SectionHeader firstHeader = ntp1.getMediatorForTesting().getSectionHeaderForTesting(); SectionHeader firstHeader = ntp1.getMediatorForTesting().getSectionHeaderForTesting();
RecyclerView.Adapter adapter1 = RecyclerView.Adapter adapter1 = ((RecyclerView) ntp1.getStream().getView()).getAdapter();
((RecyclerView) ntp1.getCoordinatorForTesting().getStream().getView()).getAdapter();
// Check header is expanded. // Check header is expanded.
Assert.assertTrue(firstHeader.isExpandable() && firstHeader.isExpanded()); Assert.assertTrue(firstHeader.isExpandable() && firstHeader.isExpanded());
...@@ -213,7 +211,7 @@ public class FeedNewTabPageTest { ...@@ -213,7 +211,7 @@ public class FeedNewTabPageTest {
Assert.assertTrue(getPreferenceForArticleSectionHeader()); Assert.assertTrue(getPreferenceForArticleSectionHeader());
// Toggle header on the current tab. // Toggle header on the current tab.
toggleHeader((ViewGroup) ntp1.getCoordinatorForTesting().getStream().getView(), false); toggleHeader((ViewGroup) ntp1.getStream().getView(), false);
// Check header is collapsed. // Check header is collapsed.
Assert.assertTrue(firstHeader.isExpandable() && !firstHeader.isExpanded()); Assert.assertTrue(firstHeader.isExpandable() && !firstHeader.isExpanded());
...@@ -224,8 +222,7 @@ public class FeedNewTabPageTest { ...@@ -224,8 +222,7 @@ public class FeedNewTabPageTest {
Tab tab2 = mActivityTestRule.loadUrlInNewTab(UrlConstants.NTP_URL); Tab tab2 = mActivityTestRule.loadUrlInNewTab(UrlConstants.NTP_URL);
FeedNewTabPage ntp2 = (FeedNewTabPage) tab2.getNativePage(); FeedNewTabPage ntp2 = (FeedNewTabPage) tab2.getNativePage();
SectionHeader secondHeader = ntp2.getMediatorForTesting().getSectionHeaderForTesting(); SectionHeader secondHeader = ntp2.getMediatorForTesting().getSectionHeaderForTesting();
RecyclerView.Adapter adapter2 = RecyclerView.Adapter adapter2 = ((RecyclerView) ntp2.getStream().getView()).getAdapter();
((RecyclerView) ntp2.getCoordinatorForTesting().getStream().getView()).getAdapter();
// Check header on the second tab is collapsed. // Check header on the second tab is collapsed.
Assert.assertTrue(secondHeader.isExpandable() && !secondHeader.isExpanded()); Assert.assertTrue(secondHeader.isExpandable() && !secondHeader.isExpanded());
...@@ -233,7 +230,7 @@ public class FeedNewTabPageTest { ...@@ -233,7 +230,7 @@ public class FeedNewTabPageTest {
Assert.assertFalse(getPreferenceForArticleSectionHeader()); Assert.assertFalse(getPreferenceForArticleSectionHeader());
// Toggle header on the second tab. // Toggle header on the second tab.
toggleHeader((ViewGroup) ntp2.getCoordinatorForTesting().getStream().getView(), true); toggleHeader((ViewGroup) ntp2.getStream().getView(), true);
// Check header on the second tab is expanded. // Check header on the second tab is expanded.
Assert.assertTrue(secondHeader.isExpandable() && secondHeader.isExpanded()); Assert.assertTrue(secondHeader.isExpandable() && secondHeader.isExpanded());
...@@ -260,21 +257,19 @@ public class FeedNewTabPageTest { ...@@ -260,21 +257,19 @@ public class FeedNewTabPageTest {
// Policy is disabled. Verify the NTP root view contains only the Stream view as child. // Policy is disabled. Verify the NTP root view contains only the Stream view as child.
ViewGroup rootView = (ViewGroup) mNtp.getView(); ViewGroup rootView = (ViewGroup) mNtp.getView();
ViewUtils.waitForStableView(rootView); ViewUtils.waitForStableView(rootView);
Assert.assertNotNull(mNtp.getCoordinatorForTesting().getStream()); Assert.assertNotNull(mNtp.getStream());
Assert.assertNull(mNtp.getCoordinatorForTesting().getScrollViewForPolicy()); Assert.assertNull(mNtp.getScrollViewForPolicy());
Assert.assertEquals(1, rootView.getChildCount()); Assert.assertEquals(1, rootView.getChildCount());
Assert.assertEquals( Assert.assertEquals(mNtp.getStream().getView(), rootView.getChildAt(0));
mNtp.getCoordinatorForTesting().getStream().getView(), rootView.getChildAt(0));
// Simulate that policy is enabled. Verify the NTP root view contains only the view for // Simulate that policy is enabled. Verify the NTP root view contains only the view for
// policy as child. // policy as child.
TestThreadUtils.runOnUiThreadBlocking(() -> PrefServiceBridge.getInstance().setBoolean( TestThreadUtils.runOnUiThreadBlocking(() -> PrefServiceBridge.getInstance().setBoolean(
Pref.NTP_ARTICLES_SECTION_ENABLED, false)); Pref.NTP_ARTICLES_SECTION_ENABLED, false));
Assert.assertNotNull(mNtp.getCoordinatorForTesting().getScrollViewForPolicy()); Assert.assertNotNull(mNtp.getScrollViewForPolicy());
Assert.assertNull(mNtp.getCoordinatorForTesting().getStream()); Assert.assertNull(mNtp.getStream());
Assert.assertEquals(1, rootView.getChildCount()); Assert.assertEquals(1, rootView.getChildCount());
Assert.assertEquals( Assert.assertEquals(mNtp.getScrollViewForPolicy(), rootView.getChildAt(0));
mNtp.getCoordinatorForTesting().getScrollViewForPolicy(), rootView.getChildAt(0));
// Open a new tab while policy is still enabled. // Open a new tab while policy is still enabled.
Tab tab2 = mActivityTestRule.loadUrlInNewTab(UrlConstants.NTP_URL); Tab tab2 = mActivityTestRule.loadUrlInNewTab(UrlConstants.NTP_URL);
...@@ -282,29 +277,26 @@ public class FeedNewTabPageTest { ...@@ -282,29 +277,26 @@ public class FeedNewTabPageTest {
ViewGroup rootView2 = (ViewGroup) ntp2.getView(); ViewGroup rootView2 = (ViewGroup) ntp2.getView();
// Verify that NTP root view contains only the view for policy as child. // Verify that NTP root view contains only the view for policy as child.
Assert.assertNotNull(ntp2.getCoordinatorForTesting().getScrollViewForPolicy()); Assert.assertNotNull(ntp2.getScrollViewForPolicy());
Assert.assertNull(ntp2.getCoordinatorForTesting().getStream()); Assert.assertNull(ntp2.getStream());
Assert.assertEquals(1, rootView2.getChildCount()); Assert.assertEquals(1, rootView2.getChildCount());
Assert.assertEquals( Assert.assertEquals(ntp2.getScrollViewForPolicy(), rootView2.getChildAt(0));
ntp2.getCoordinatorForTesting().getScrollViewForPolicy(), rootView2.getChildAt(0));
// Simulate that policy is disabled. Verify the NTP root view is the view for policy. We // Simulate that policy is disabled. Verify the NTP root view is the view for policy. We
// don't re-enable the Feed until the next restart. // don't re-enable the Feed until the next restart.
TestThreadUtils.runOnUiThreadBlocking(() -> PrefServiceBridge.getInstance().setBoolean( TestThreadUtils.runOnUiThreadBlocking(() -> PrefServiceBridge.getInstance().setBoolean(
Pref.NTP_ARTICLES_SECTION_ENABLED, true)); Pref.NTP_ARTICLES_SECTION_ENABLED, true));
Assert.assertNotNull(ntp2.getCoordinatorForTesting().getScrollViewForPolicy()); Assert.assertNotNull(ntp2.getScrollViewForPolicy());
Assert.assertNull(ntp2.getCoordinatorForTesting().getStream()); Assert.assertNull(ntp2.getStream());
Assert.assertEquals(1, rootView2.getChildCount()); Assert.assertEquals(1, rootView2.getChildCount());
Assert.assertEquals( Assert.assertEquals(ntp2.getScrollViewForPolicy(), rootView2.getChildAt(0));
ntp2.getCoordinatorForTesting().getScrollViewForPolicy(), rootView2.getChildAt(0));
// Switch to the old tab. Verify the NTP root view is the view for policy. // Switch to the old tab. Verify the NTP root view is the view for policy.
ChromeTabUtils.switchTabInCurrentTabModel(mActivityTestRule.getActivity(), mTab.getId()); ChromeTabUtils.switchTabInCurrentTabModel(mActivityTestRule.getActivity(), mTab.getId());
Assert.assertNotNull(mNtp.getCoordinatorForTesting().getScrollViewForPolicy()); Assert.assertNotNull(mNtp.getScrollViewForPolicy());
Assert.assertNull(mNtp.getCoordinatorForTesting().getStream()); Assert.assertNull(mNtp.getStream());
Assert.assertEquals(1, rootView.getChildCount()); Assert.assertEquals(1, rootView.getChildCount());
Assert.assertEquals( Assert.assertEquals(mNtp.getScrollViewForPolicy(), rootView.getChildAt(0));
mNtp.getCoordinatorForTesting().getScrollViewForPolicy(), rootView.getChildAt(0));
// Reset state. // Reset state.
TestThreadUtils.runOnUiThreadBlocking(() -> PrefServiceBridge.getInstance().setBoolean( TestThreadUtils.runOnUiThreadBlocking(() -> PrefServiceBridge.getInstance().setBoolean(
......
...@@ -46,7 +46,7 @@ import org.chromium.chrome.browser.tab.Tab.TabHidingType; ...@@ -46,7 +46,7 @@ import org.chromium.chrome.browser.tab.Tab.TabHidingType;
*/ */
@RunWith(BaseRobolectricTestRunner.class) @RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE) @Config(manifest = Config.NONE)
public class NtpStreamLifecycleManagerTest { public class StreamLifecycleManagerTest {
@Mock @Mock
private Activity mActivity; private Activity mActivity;
@Mock @Mock
...@@ -56,7 +56,7 @@ public class NtpStreamLifecycleManagerTest { ...@@ -56,7 +56,7 @@ public class NtpStreamLifecycleManagerTest {
@Mock @Mock
private PrefServiceBridge mPrefServiceBridge; private PrefServiceBridge mPrefServiceBridge;
private NtpStreamLifecycleManager mNtpStreamLifecycleManager; private StreamLifecycleManager mStreamLifecycleManager;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -68,7 +68,7 @@ public class NtpStreamLifecycleManagerTest { ...@@ -68,7 +68,7 @@ public class NtpStreamLifecycleManagerTest {
PrefServiceBridge.setInstanceForTesting(mPrefServiceBridge); PrefServiceBridge.setInstanceForTesting(mPrefServiceBridge);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.CREATED); ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.CREATED);
mNtpStreamLifecycleManager = new NtpStreamLifecycleManager(mStream, mActivity, mTab); mStreamLifecycleManager = new StreamLifecycleManager(mStream, mActivity, mTab);
verify(mStream, times(1)).onCreate(or(any(String.class), isNull())); verify(mStream, times(1)).onCreate(or(any(String.class), isNull()));
} }
...@@ -83,7 +83,7 @@ public class NtpStreamLifecycleManagerTest { ...@@ -83,7 +83,7 @@ public class NtpStreamLifecycleManagerTest {
// Verify that onShow is not called before activity started. // Verify that onShow is not called before activity started.
when(mTab.isHidden()).thenReturn(false); when(mTab.isHidden()).thenReturn(false);
when(mTab.isUserInteractable()).thenReturn(true); when(mTab.isUserInteractable()).thenReturn(true);
mNtpStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW); mStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW);
verify(mStream, times(0)).onShow(); verify(mStream, times(0)).onShow();
// Verify that onShow is not called when Tab is hidden. // Verify that onShow is not called when Tab is hidden.
...@@ -93,11 +93,11 @@ public class NtpStreamLifecycleManagerTest { ...@@ -93,11 +93,11 @@ public class NtpStreamLifecycleManagerTest {
// Verify that onShow is called when Tab is shown and activity is started. // Verify that onShow is called when Tab is shown and activity is started.
when(mTab.isHidden()).thenReturn(false); when(mTab.isHidden()).thenReturn(false);
mNtpStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW); mStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW);
verify(mStream, times(1)).onShow(); verify(mStream, times(1)).onShow();
// When the Stream is shown, it won't call Stream#onShow() again. // When the Stream is shown, it won't call Stream#onShow() again.
mNtpStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW); mStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW);
verify(mStream, times(1)).onShow(); verify(mStream, times(1)).onShow();
} }
...@@ -109,22 +109,22 @@ public class NtpStreamLifecycleManagerTest { ...@@ -109,22 +109,22 @@ public class NtpStreamLifecycleManagerTest {
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED);
when(mTab.isHidden()).thenReturn(false); when(mTab.isHidden()).thenReturn(false);
when(mTab.isUserInteractable()).thenReturn(true); when(mTab.isUserInteractable()).thenReturn(true);
mNtpStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW); mStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW);
verify(mStream, times(0)).onShow(); verify(mStream, times(0)).onShow();
// Verify that onShow is called when articles are set shown by the user. // Verify that onShow is called when articles are set shown by the user.
when(mPrefServiceBridge.getBoolean(Pref.NTP_ARTICLES_LIST_VISIBLE)).thenReturn(true); when(mPrefServiceBridge.getBoolean(Pref.NTP_ARTICLES_LIST_VISIBLE)).thenReturn(true);
mNtpStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW); mStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW);
verify(mStream, times(1)).onShow(); verify(mStream, times(1)).onShow();
// Verify that onHide is called after tab is hidden. // Verify that onHide is called after tab is hidden.
mNtpStreamLifecycleManager.getTabObserverForTesting().onHidden(mTab, CHANGED_TABS); mStreamLifecycleManager.getTabObserverForTesting().onHidden(mTab, CHANGED_TABS);
verify(mStream, times(1)).onHide(); verify(mStream, times(1)).onHide();
// Verify that onShow is called when articles are set hidden by the user within the same // Verify that onShow is called when articles are set hidden by the user within the same
// session. // session.
when(mPrefServiceBridge.getBoolean(Pref.NTP_ARTICLES_LIST_VISIBLE)).thenReturn(false); when(mPrefServiceBridge.getBoolean(Pref.NTP_ARTICLES_LIST_VISIBLE)).thenReturn(false);
mNtpStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW); mStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW);
verify(mStream, times(2)).onShow(); verify(mStream, times(2)).onShow();
} }
...@@ -146,7 +146,7 @@ public class NtpStreamLifecycleManagerTest { ...@@ -146,7 +146,7 @@ public class NtpStreamLifecycleManagerTest {
// Verify that stream is active when tab is user interactable and activity is resumed. // Verify that stream is active when tab is user interactable and activity is resumed.
when(mTab.isUserInteractable()).thenReturn(true); when(mTab.isUserInteractable()).thenReturn(true);
mNtpStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(true); mStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(true);
verify(mStream, times(1)).onShow(); verify(mStream, times(1)).onShow();
verify(mStream, times(1)).onActive(); verify(mStream, times(1)).onActive();
...@@ -208,7 +208,7 @@ public class NtpStreamLifecycleManagerTest { ...@@ -208,7 +208,7 @@ public class NtpStreamLifecycleManagerTest {
verify(mStream, times(1)).onInactive(); verify(mStream, times(1)).onInactive();
// When the Stream is inactive, it won't call Stream#onInactive() again. // When the Stream is inactive, it won't call Stream#onInactive() again.
mNtpStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(false); mStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(false);
verify(mStream, times(1)).onInactive(); verify(mStream, times(1)).onInactive();
// Verify that the Stream cannot be set shown from inactive. // Verify that the Stream cannot be set shown from inactive.
...@@ -220,7 +220,7 @@ public class NtpStreamLifecycleManagerTest { ...@@ -220,7 +220,7 @@ public class NtpStreamLifecycleManagerTest {
verify(mStream, times(2)).onActive(); verify(mStream, times(2)).onActive();
// Verify that the Stream can be set inactive from active on tab interactability changed. // Verify that the Stream can be set inactive from active on tab interactability changed.
mNtpStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(false); mStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(false);
verify(mStream, times(2)).onInactive(); verify(mStream, times(2)).onInactive();
} }
...@@ -260,7 +260,7 @@ public class NtpStreamLifecycleManagerTest { ...@@ -260,7 +260,7 @@ public class NtpStreamLifecycleManagerTest {
verify(mStream, times(1)).onShow(); verify(mStream, times(1)).onShow();
// Verify that onActive and onInactive are skipped when Stream is set hidden from shown. // Verify that onActive and onInactive are skipped when Stream is set hidden from shown.
mNtpStreamLifecycleManager.getTabObserverForTesting().onHidden( mStreamLifecycleManager.getTabObserverForTesting().onHidden(
mTab, TabHidingType.CHANGED_TABS); mTab, TabHidingType.CHANGED_TABS);
verify(mStream, times(1)).onShow(); verify(mStream, times(1)).onShow();
verify(mStream, times(0)).onActive(); verify(mStream, times(0)).onActive();
...@@ -281,7 +281,7 @@ public class NtpStreamLifecycleManagerTest { ...@@ -281,7 +281,7 @@ public class NtpStreamLifecycleManagerTest {
public void testDestroyAfterCreate() { public void testDestroyAfterCreate() {
// After the Stream is destroyed, lifecycle methods should never be called. Directly calling // After the Stream is destroyed, lifecycle methods should never be called. Directly calling
// destroy here to simulate destroy() being called on FeedNewTabPage destroyed. // destroy here to simulate destroy() being called on FeedNewTabPage destroyed.
mNtpStreamLifecycleManager.destroy(); mStreamLifecycleManager.destroy();
verify(mStream, times(1)).onDestroy(); verify(mStream, times(1)).onDestroy();
// Verify that lifecycle methods are not called after destroy. // Verify that lifecycle methods are not called after destroy.
...@@ -386,33 +386,33 @@ public class NtpStreamLifecycleManagerTest { ...@@ -386,33 +386,33 @@ public class NtpStreamLifecycleManagerTest {
// On tab shown. // On tab shown.
when(mTab.isHidden()).thenReturn(false); when(mTab.isHidden()).thenReturn(false);
mNtpStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW); mStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_NEW);
inOrder.verify(mStream).onShow(); inOrder.verify(mStream).onShow();
verify(mStream, times(1)).onShow(); verify(mStream, times(1)).onShow();
// On tab interactable. // On tab interactable.
when(mTab.isUserInteractable()).thenReturn(true); when(mTab.isUserInteractable()).thenReturn(true);
mNtpStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(true); mStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(true);
inOrder.verify(mStream).onActive(); inOrder.verify(mStream).onActive();
verify(mStream, times(1)).onActive(); verify(mStream, times(1)).onActive();
// On tab un-interactable (simulates user enter the tab switcher). // On tab un-interactable (simulates user enter the tab switcher).
when(mTab.isUserInteractable()).thenReturn(false); when(mTab.isUserInteractable()).thenReturn(false);
mNtpStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(false); mStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(false);
inOrder.verify(mStream).onInactive(); inOrder.verify(mStream).onInactive();
verify(mStream, times(1)).onInactive(); verify(mStream, times(1)).onInactive();
// On tab interactable (simulates user exit the tab switcher). // On tab interactable (simulates user exit the tab switcher).
when(mTab.isUserInteractable()).thenReturn(true); when(mTab.isUserInteractable()).thenReturn(true);
mNtpStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(true); mStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(true);
inOrder.verify(mStream).onActive(); inOrder.verify(mStream).onActive();
verify(mStream, times(2)).onActive(); verify(mStream, times(2)).onActive();
// On tab un-interactable and hidden (simulates user switch to another tab). // On tab un-interactable and hidden (simulates user switch to another tab).
when(mTab.isHidden()).thenReturn(true); when(mTab.isHidden()).thenReturn(true);
when(mTab.isUserInteractable()).thenReturn(false); when(mTab.isUserInteractable()).thenReturn(false);
mNtpStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(false); mStreamLifecycleManager.getTabObserverForTesting().onInteractabilityChanged(false);
mNtpStreamLifecycleManager.getTabObserverForTesting().onHidden(mTab, CHANGED_TABS); mStreamLifecycleManager.getTabObserverForTesting().onHidden(mTab, CHANGED_TABS);
inOrder.verify(mStream).onInactive(); inOrder.verify(mStream).onInactive();
inOrder.verify(mStream).onHide(); inOrder.verify(mStream).onHide();
verify(mStream, times(2)).onInactive(); verify(mStream, times(2)).onInactive();
...@@ -420,12 +420,12 @@ public class NtpStreamLifecycleManagerTest { ...@@ -420,12 +420,12 @@ public class NtpStreamLifecycleManagerTest {
// On tab shown (simulates user switch back to this tab). // On tab shown (simulates user switch back to this tab).
when(mTab.isHidden()).thenReturn(false); when(mTab.isHidden()).thenReturn(false);
mNtpStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_USER); mStreamLifecycleManager.getTabObserverForTesting().onShown(mTab, FROM_USER);
inOrder.verify(mStream).onShow(); inOrder.verify(mStream).onShow();
verify(mStream, times(2)).onShow(); verify(mStream, times(2)).onShow();
// On tab destroy (simulates user close the tab or navigate to another URL). // On tab destroy (simulates user close the tab or navigate to another URL).
mNtpStreamLifecycleManager.destroy(); mStreamLifecycleManager.destroy();
inOrder.verify(mStream).onHide(); inOrder.verify(mStream).onHide();
inOrder.verify(mStream).onDestroy(); inOrder.verify(mStream).onDestroy();
verify(mStream, times(2)).onHide(); verify(mStream, times(2)).onHide();
......
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