blob: 82ccec713fdaabeba9fd8e4abb47364046cf2dec [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// 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.omnibox.suggestions.base;
import android.content.Context;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.chromium.chrome.browser.omnibox.OmniboxFeatures;
import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
import org.chromium.chrome.browser.omnibox.suggestions.ActionChipsDelegate;
import org.chromium.chrome.browser.omnibox.suggestions.FaviconFetcher;
import org.chromium.chrome.browser.omnibox.suggestions.SuggestionHost;
import org.chromium.chrome.browser.omnibox.suggestions.SuggestionsMetrics;
import org.chromium.chrome.browser.omnibox.suggestions.basic.BasicSuggestionProcessor;
import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties;
import org.chromium.components.omnibox.AutocompleteMatch;
import org.chromium.components.omnibox.action.HistoryClustersAction;
import org.chromium.components.omnibox.action.OmniboxAction;
import org.chromium.components.omnibox.action.OmniboxActionType;
import org.chromium.ui.modelutil.PropertyModel;
import java.util.List;
/**
* Processor for a "row UI" history clusters suggestion, i.e. one that navigates to the Journeys
* page directly instead of hosting a chip that navigates to the Journeys page.
*/
public class HistoryClustersProcessor extends BasicSuggestionProcessor {
private final OpenHistoryClustersDelegate mOpenHistoryClustersDelegate;
private final Context mContext;
private int mJourneysActionShownPosition = -1;
/** Delegate for HistoryClusters-related logic that omnibox code can't perform for itself. */
public interface OpenHistoryClustersDelegate {
void openHistoryClustersUi(String query);
}
/**
* See {@link BasicSuggestionProcessor#BasicSuggestionProcessor(Context, SuggestionHost,
* ActionChipsDelegate, UrlBarEditingTextStateProvider, FaviconFetcher, BookmarkState)}
*/
public HistoryClustersProcessor(OpenHistoryClustersDelegate openHistoryClustersDelegate,
@NonNull Context context, @NonNull SuggestionHost suggestionHost,
@NonNull UrlBarEditingTextStateProvider editingTextProvider,
@NonNull FaviconFetcher faviconFetcher, @NonNull BookmarkState bookmarkState) {
super(context, suggestionHost, null, editingTextProvider, faviconFetcher, bookmarkState);
mOpenHistoryClustersDelegate = openHistoryClustersDelegate;
mContext = context;
}
@Override
public void onUrlFocusChange(boolean hasFocus) {
super.onUrlFocusChange(hasFocus);
if (!hasFocus) {
SuggestionsMetrics.recordResumeJourneyShown(mJourneysActionShownPosition);
}
}
@Override
public boolean doesProcessSuggestion(AutocompleteMatch suggestion, int position) {
if (!OmniboxFeatures.isJourneysRowUiEnabled()) {
return false;
}
HistoryClustersAction action = getHistoryClustersAction(suggestion);
if (action == null) return false;
assert !TextUtils.isEmpty(action.query);
return true;
}
@Override
public void populateModel(AutocompleteMatch suggestion, PropertyModel model, int position) {
HistoryClustersAction pedal = getHistoryClustersAction(suggestion);
if (pedal == null) return;
super.populateModel(suggestion, model, position);
model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT, new SuggestionSpannable(pedal.hint));
model.set(BaseSuggestionViewProperties.ON_CLICK,
() -> onJourneysSuggestionClicked(pedal, position));
model.set(BaseSuggestionViewProperties.ON_LONG_CLICK,
() -> onJourneysSuggestionClicked(pedal, position));
SuggestionDrawableState sds =
SuggestionDrawableState.Builder.forDrawableRes(mContext, pedal.icon.iconRes)
.setAllowTint(false)
.build();
model.set(BaseSuggestionViewProperties.ICON, sds);
// We want to behave like a search suggestion w.r.t. secondary text coloring.
model.set(SuggestionViewProperties.IS_SEARCH_SUGGESTION, true);
setActionButtons(model, null);
mJourneysActionShownPosition = position;
}
private void onJourneysSuggestionClicked(HistoryClustersAction action, int position) {
if (mOpenHistoryClustersDelegate != null) {
String query = action.query;
SuggestionsMetrics.recordResumeJourneyClick(position);
mOpenHistoryClustersDelegate.openHistoryClustersUi(query);
}
}
/**
* Returns the associated history clusters action for a suggestion if one exists. Returns null
* if:
* * No history clusters actions is present.
* * The suggestion has 0 associated actions.
* * The suggestion has >1 associated actions.
* */
private static @Nullable HistoryClustersAction getHistoryClustersAction(
AutocompleteMatch suggestion) {
List<OmniboxAction> actions = suggestion.getActions();
if (actions.size() != 1) return null;
OmniboxAction action = actions.get(0);
if (action.actionId == OmniboxActionType.HISTORY_CLUSTERS) {
return HistoryClustersAction.from(action);
}
return null;
}
}