blob: 1f7e6eca16f4212d06fb8163980f28238b2755f7 [file] [log] [blame]
// 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.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.Destroyable;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* Represents the entry point for the TabSuggestions component. Responsible for
* registering and invoking the different {@link TabSuggestionsFetcher}.
*/
public class TabSuggestionsOrchestrator implements TabSuggestions, Destroyable {
public static final String TAB_SUGGESTIONS_UMA_PREFIX = "TabSuggestionsOrchestrator";
private static final String TAG = "TabSuggestionsDetailed";
private static final int MIN_CLOSE_SUGGESTIONS_THRESHOLD = 3;
protected TabContextObserver mTabContextObserver;
private final ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
private List<TabSuggestionsFetcher> mTabSuggestionsFetchers;
private List<TabSuggestion> mPrefetchedResults = new LinkedList<>();
private TabContext mPrefetchedTabContext;
private TabModelSelector mTabModelSelector;
public TabSuggestionsOrchestrator(
TabModelSelector selector, ActivityLifecycleDispatcher activityLifecycleDispatcher) {
mTabModelSelector = selector;
mTabSuggestionsFetchers = new LinkedList<>();
mTabSuggestionsFetchers.add(new TabSuggestionsClientFetcher());
mTabContextObserver = new TabContextObserver(selector) {
@Override
public void onTabContextChanged(@TabContextChangeReason int changeReason) {
prefetchSuggestions();
}
};
mActivityLifecycleDispatcher = activityLifecycleDispatcher;
activityLifecycleDispatcher.register(this);
}
@Override
public List<TabSuggestion> getSuggestions(TabContext tabContext) {
synchronized (mPrefetchedResults) {
if (tabContext.equals(mPrefetchedTabContext)) {
return aggregateResults(mPrefetchedResults);
}
return new LinkedList<>();
}
}
private List<TabSuggestion> aggregateResults(List<TabSuggestion> tabSuggestions) {
List<TabSuggestion> aggregated = new LinkedList<>();
for (TabSuggestion tabSuggestion : tabSuggestions) {
switch (tabSuggestion.getAction()) {
case TabSuggestion.TabSuggestionAction.CLOSE:
if (tabSuggestion.getTabsInfo().size() >= MIN_CLOSE_SUGGESTIONS_THRESHOLD) {
aggregated.add(tabSuggestion);
}
break;
case TabSuggestion.TabSuggestionAction.GROUP:
if (!tabSuggestion.getTabsInfo().isEmpty()) {
aggregated.add(tabSuggestion);
}
break;
default:
android.util.Log.e(
TAG, String.format("Unknown action: %d", tabSuggestion.getAction()));
break;
}
}
Collections.shuffle(aggregated);
return aggregated;
}
@Override
public void destroy() {
mTabContextObserver.destroy();
mActivityLifecycleDispatcher.unregister(this);
}
/**
* Acquire suggestions and store so suggestions are available for the UI
* thread on demand.
*/
protected void prefetchSuggestions() {
TabContext tabContext = TabContext.createCurrentContext(mTabModelSelector);
synchronized (mPrefetchedResults) {
mPrefetchedTabContext = tabContext;
mPrefetchedResults = new LinkedList<>();
for (TabSuggestionsFetcher tabSuggestionsFetcher : mTabSuggestionsFetchers) {
if (tabSuggestionsFetcher.isEnabled()) {
tabSuggestionsFetcher.fetch(tabContext, res -> prefetchCallback(res));
}
}
}
}
private void prefetchCallback(TabSuggestionsFetcherResults suggestions) {
synchronized (mPrefetchedResults) {
if (suggestions.tabContext.equals(mPrefetchedTabContext)) {
mPrefetchedResults.addAll(suggestions.tabSuggestions);
}
}
}
}