blob: cfb478718761cfa4ebddb13fa2672a9caea2de32 [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;
import android.content.Context;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.Callback;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModelFilter;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabContext;
import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestion;
import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionFeedback;
import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionsObserver;
import org.chromium.chrome.tab_ui.R;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* One of the concrete {@link MessageService} that only serve {@link MessageType.TAB_SUGGESTION}.
*/
public class TabSuggestionMessageService extends MessageService implements TabSuggestionsObserver {
static final int CLOSE_SUGGESTION_ACTION_ENABLING_THRESHOLD = 1;
/**
* This is the data type that this MessageService is serving to its Observer.
*/
public class TabSuggestionMessageData implements MessageData {
public final TabSuggestion tabSuggestion;
public final MessageCardView.ReviewActionProvider reviewActionProvider;
public final MessageCardView.DismissActionProvider dismissActionProvider;
public TabSuggestionMessageData(TabSuggestion tabSuggestion,
MessageCardView.ReviewActionProvider reviewActionProvider,
MessageCardView.DismissActionProvider dismissActionProvider) {
this.tabSuggestion = tabSuggestion;
this.reviewActionProvider = reviewActionProvider;
this.dismissActionProvider = dismissActionProvider;
}
}
private final Context mContext;
private final TabModelSelector mTabModelSelector;
private TabSelectionEditorCoordinator
.TabSelectionEditorController mTabSelectionEditorController;
private TabSuggestion mCurrentBestTabSuggestion;
public TabSuggestionMessageService(Context context, TabModelSelector tabModelSelector,
TabSelectionEditorCoordinator
.TabSelectionEditorController tabSelectionEditorController) {
super(MessageType.TAB_SUGGESTION);
mContext = context;
mTabModelSelector = tabModelSelector;
mTabSelectionEditorController = tabSelectionEditorController;
}
@VisibleForTesting
void review() {
assert mCurrentBestTabSuggestion != null;
mTabSelectionEditorController.configureToolbar(getActionString(mCurrentBestTabSuggestion),
getActionProvider(mCurrentBestTabSuggestion),
getEnablingThreshold(mCurrentBestTabSuggestion), null);
mTabSelectionEditorController.show(
getTabList(), mCurrentBestTabSuggestion.getTabsInfo().size());
}
private String getActionString(TabSuggestion tabSuggestion) {
switch (tabSuggestion.getAction()) {
case TabSuggestion.TabSuggestionAction.CLOSE:
return mContext.getString(R.string.tab_suggestion_close_tab_action_button);
default:
assert false;
}
return null;
}
private int getEnablingThreshold(TabSuggestion tabSuggestion) {
switch (tabSuggestion.getAction()) {
case TabSuggestion.TabSuggestionAction.CLOSE:
return CLOSE_SUGGESTION_ACTION_ENABLING_THRESHOLD;
default:
assert false;
}
return -1;
}
@VisibleForTesting
TabSelectionEditorActionProvider getActionProvider(TabSuggestion tabSuggestion) {
switch (tabSuggestion.getAction()) {
case TabSuggestion.TabSuggestionAction.CLOSE:
return new TabSelectionEditorActionProvider(mTabSelectionEditorController,
TabSelectionEditorActionProvider.TabSelectionEditorAction.CLOSE) {
@Override
void processSelectedTabs(
List<Tab> selectedTabs, TabModelSelector tabModelSelector) {
super.processSelectedTabs(selectedTabs, tabModelSelector);
// TODO(crbug.com/1023699) : call TabSuggestion component suggestion
// acceptance callback.
}
};
default:
assert false;
}
return null;
}
private List<Tab> getTabList() {
List<Tab> tabs = new ArrayList<>();
Set<Integer> suggestedTabIds = new HashSet<>();
List<TabContext.TabInfo> suggestedTabInfo = mCurrentBestTabSuggestion.getTabsInfo();
for (int i = 0; i < suggestedTabInfo.size(); i++) {
suggestedTabIds.add(suggestedTabInfo.get(i).id);
tabs.add(mTabModelSelector.getTabById(suggestedTabInfo.get(i).id));
}
tabs.addAll(getNonSuggestedTabs(suggestedTabIds));
return tabs;
}
private List<Tab> getNonSuggestedTabs(Set<Integer> suggestedTabIds) {
List<Tab> tabs = new ArrayList<>();
TabModelFilter tabModelFilter =
mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter();
List<Tab> filteredTab = tabModelFilter.getTabsWithNoOtherRelatedTabs();
for (int i = 0; i < filteredTab.size(); i++) {
Tab tab = filteredTab.get(i);
if (!suggestedTabIds.contains(tab.getId())) tabs.add(tab);
}
return tabs;
}
private void dismiss() {
// TODO(crbug.com/1023699): run dismiss callback from onNewSuggestion().
}
// TabSuggestionObserver implementations.
@Override
public void onNewSuggestion(List<TabSuggestion> tabSuggestions,
Callback<TabSuggestionFeedback> tabSuggestionFeedback) {
if (tabSuggestions.size() == 0) return;
mCurrentBestTabSuggestion = tabSuggestions.get(0);
sendAvailabilityNotification(new TabSuggestionMessageData(
mCurrentBestTabSuggestion, this::review, this::dismiss));
}
@Override
public void onTabSuggestionInvalidated() {
mCurrentBestTabSuggestion = null;
sendInvalidNotification();
}
}