Commit 97e508e4 authored by David Maunder's avatar David Maunder Committed by Commit Bot

Add TabSuggestionsClientFetcher

This component aggregates client side tab suggestions for closing tabs.

Bug: 1005385
Change-Id: I797b983737441edd4f8e1a155ea94708219765c6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1811717
Commit-Queue: David Maunder <davidjm@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#700369}
parent 2d369b47
......@@ -139,6 +139,9 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextObserver.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsFetcher.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsFetcherResults.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsClientFetcher.java",
]
deps = [
......
// 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.browser.tasks.tab_management.suggestions;
import org.chromium.base.Callback;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Implements {@link TabSuggestionsFetcher}. Abstracts the details of
* communicating with all known client-side {@link TabSuggestionProvider}
*/
public final class TabSuggestionsClientFetcher implements TabSuggestionsFetcher {
private List<TabSuggestionProvider> mClientSuggestionProviders;
/**
* Acquires suggestions for which tabs to close based on client side
* heuristics.
*/
public TabSuggestionsClientFetcher() {
mClientSuggestionProviders =
new ArrayList<>(Arrays.asList(new StaleTabSuggestionProvider()));
}
@Override
public void fetch(TabContext tabContext, Callback<TabSuggestionsFetcherResults> callback) {
List<TabSuggestion> retList = new ArrayList<>();
for (TabSuggestionProvider provider : mClientSuggestionProviders) {
List<TabSuggestion> suggestions = provider.suggest(tabContext);
if (suggestions != null && !suggestions.isEmpty()) {
retList.addAll(suggestions);
}
}
callback.onResult(new TabSuggestionsFetcherResults(retList, tabContext));
}
@Override
public boolean isEnabled() {
return true;
}
}
// 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.browser.tasks.tab_management.suggestions;
import org.chromium.base.Callback;
/**
* Defines the interface for suggestion fetchers.
*/
public interface TabSuggestionsFetcher {
/**
* Acquires suggestions for closing tabs based on client side heuristics
* and returns the result in a callback
* @param tabContext snapshot of current tab and tab groups
* @param callback callback the results are returned in
*/
void fetch(TabContext tabContext, Callback<TabSuggestionsFetcherResults> callback);
/**
* Returns true if the Fetcher is enabled.
*/
boolean isEnabled();
}
// 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.browser.tasks.tab_management.suggestions;
import java.util.List;
/**
* Represents results for recommendations regarding whether Tabs should be
* closed.
*/
public class TabSuggestionsFetcherResults {
public final List<TabSuggestion> tabSuggestions;
public final TabContext tabContext;
/**
* Results from Tab suggestions fetcher
* @param tabSuggestions tabs suggested to be closed
* @param tabContext snapshot of current tab and tab groups
*/
TabSuggestionsFetcherResults(List<TabSuggestion> tabSuggestions, TabContext tabContext) {
this.tabSuggestions = tabSuggestions;
this.tabContext = tabContext;
}
}
// 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.browser.tasks.tab_management.suggestions;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.chromium.base.Callback;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.testing.local.LocalRobolectricTestRunner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Test TabSuggestionsClientFetcher
*/
@RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class TabSuggestionsClientFetcherTest {
@Rule
public TestRule mProcessor = new Features.JUnitProcessor();
@Mock
TabContext mTabContext;
@Mock
private Callback<TabSuggestionsFetcherResults> mTabSuggestionsFetcherResultsCallback;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
/**
* Test when client fetcher has results
*/
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
"enable-features=" + ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<FakeStudyName",
"force-fieldtrials=FakeStudyName/Enabled",
"force-fieldtrial-params=FakeStudyName.Enabled:"
+ "close_tab_suggestions_stale_time_ms/86400000"})
// 86400000 milliseconds = 1 day
@Test
public void
testClientFetcher() throws Exception {
TabSuggestionsClientFetcher tabSuggestionsClientFetcher = new TabSuggestionsClientFetcher();
// Ensures we call StaleTabSuggestionsProvider by ensuring stale tabs
// are recommended to be closed.
List<TabContext.TabInfo> tabInfos = new ArrayList<>();
tabInfos.add(new TabContext.TabInfo(3, "mock_recent_title", "mock_recent_url",
"mock_recent_original_url", "mock_recent_url",
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5)));
tabInfos.add(new TabContext.TabInfo(3, "mock_stale_title", "mock_stale_url",
"mock_stale_original_url", "mock_stale_referrer_url",
System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2)));
doReturn(tabInfos).when(mTabContext).getUngroupedTabs();
tabSuggestionsClientFetcher.fetch(mTabContext, mTabSuggestionsFetcherResultsCallback);
ArgumentCaptor<TabSuggestionsFetcherResults> argument =
ArgumentCaptor.forClass(TabSuggestionsFetcherResults.class);
verify(mTabSuggestionsFetcherResultsCallback, times(1)).onResult(argument.capture());
Assert.assertEquals(1, argument.getValue().tabSuggestions.size());
TabSuggestion staleSuggestion = argument.getValue().tabSuggestions.get(0);
Assert.assertEquals("mock_stale_title", staleSuggestion.getTabsInfo().get(0).title);
Assert.assertEquals(TabSuggestion.TabSuggestionAction.CLOSE, staleSuggestion.getAction());
Assert.assertEquals(TabSuggestionsRanker.SuggestionProviders.STALE_TABS_SUGGESTION_PROVIDER,
staleSuggestion.getProviderName());
}
/**
* Test when results are null
*/
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
"enable-features=" + ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<FakeStudyName",
"force-fieldtrials=FakeStudyName/Enabled",
"force-fieldtrial-params=FakeStudyName.Enabled:"
+ "close_tab_suggestions_stale_time_ms/86400000"})
// 86400000 milliseconds = 1 day
@Test
public void
testNullResults() throws Exception {
TabSuggestionsClientFetcher tabSuggestionsClientFetcher = new TabSuggestionsClientFetcher();
doReturn(null).when(mTabContext).getUngroupedTabs();
tabSuggestionsClientFetcher.fetch(mTabContext, mTabSuggestionsFetcherResultsCallback);
ArgumentCaptor<TabSuggestionsFetcherResults> argument =
ArgumentCaptor.forClass(TabSuggestionsFetcherResults.class);
verify(mTabSuggestionsFetcherResultsCallback, times(1)).onResult(argument.capture());
Assert.assertEquals(0, argument.getValue().tabSuggestions.size());
}
/**
* Test when results are empty
*/
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
"enable-features=" + ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<FakeStudyName",
"force-fieldtrials=FakeStudyName/Enabled",
"force-fieldtrial-params=FakeStudyName.Enabled:"
+ "close_tab_suggestions_stale_time_ms/86400000"})
// 86400000 milliseconds = 1 day
@Test
public void
testEmptyResults() throws Exception {
TabSuggestionsClientFetcher tabSuggestionsClientFetcher = new TabSuggestionsClientFetcher();
doReturn(Collections.emptyList()).when(mTabContext).getUngroupedTabs();
tabSuggestionsClientFetcher.fetch(mTabContext, mTabSuggestionsFetcherResultsCallback);
ArgumentCaptor<TabSuggestionsFetcherResults> argument =
ArgumentCaptor.forClass(TabSuggestionsFetcherResults.class);
verify(mTabSuggestionsFetcherResultsCallback, times(1)).onResult(argument.capture());
Assert.assertEquals(0, argument.getValue().tabSuggestions.size());
}
}
......@@ -42,4 +42,5 @@ tab_management_junit_java_sources = [
"//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java",
"//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextObserverTest.java",
"//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java",
"//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsClientFetcherTest.java",
]
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