// Copyright 2014 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.omnibox; import android.text.TextUtils; import com.google.common.annotations.VisibleForTesting; /** * Container class with information about each omnibox suggestion item. */ @VisibleForTesting public class OmniboxSuggestion { private final Type mType; private final String mDisplayText; private final String mDescription; private final String mAnswerContents; private final String mAnswerType; private final SuggestionAnswer mAnswer; private final String mFillIntoEdit; private final String mUrl; private final String mFormattedUrl; private final int mRelevance; private final int mTransition; private final boolean mIsStarred; private final boolean mIsDeletable; /** * This should be kept in sync with AutocompleteMatch::Type * (see chrome/common/autocomplete_match_type.h). * Negative types are specific to Chrome on Android front-end. */ public static enum Type { VOICE_SUGGEST (-100), // A suggested search from the voice recognizer. URL_WHAT_YOU_TYPED (0), // The input as a URL. HISTORY_URL (1), // A past page whose URL contains the input. HISTORY_TITLE (2), // A past page whose title contains the input. HISTORY_BODY (3), // A past page whose body contains the input. HISTORY_KEYWORD (4), // A past page whose keyword contains the input. NAVSUGGEST (5), // A suggested URL. SEARCH_WHAT_YOU_TYPED (6), // The input as a search query (with the default // engine). SEARCH_HISTORY (7), // A past search (with the default engine) // containing the input. SEARCH_SUGGEST (8), // A suggested search (with the default engine). SEARCH_SUGGEST_ENTITY (9), // A suggested search for an entity. SEARCH_SUGGEST_INFINITE (10), // A suggested search (with the default engine) // to complete the tail part of the input. SEARCH_SUGGEST_PERSONALIZED (11), // A personalized suggested search. SEARCH_SUGGEST_PROFILE (12), // A personalized suggested search for a // Google+ profile. SEARCH_OTHER_ENGINE (13), // A search with a non-default engine. OPEN_HISTORY_PAGE (17), // A synthetic result that opens the history page // to search for the input. SEARCH_SUGGEST_ANSWER (18); // A short result for a suggested search. private final int mNativeType; Type(int nativeType) { mNativeType = nativeType; } static Type getTypeFromNativeType(int nativeType) { for (Type t : Type.values()) { if (t.mNativeType == nativeType) return t; } return URL_WHAT_YOU_TYPED; } public boolean isHistoryUrl() { return this == HISTORY_URL || this == HISTORY_TITLE || this == HISTORY_BODY || this == HISTORY_KEYWORD; } public boolean isUrl() { return this == URL_WHAT_YOU_TYPED || this.isHistoryUrl() || this == NAVSUGGEST; } /** * @return The ID of the type used by the native code. */ public int nativeType() { return mNativeType; } } public OmniboxSuggestion(int nativeType, int relevance, int transition, String text, String description, String answerContents, String answerType, String fillIntoEdit, String url, String formattedUrl, boolean isStarred, boolean isDeletable) { mType = Type.getTypeFromNativeType(nativeType); mRelevance = relevance; mTransition = transition; mDisplayText = text; mDescription = description; mAnswerContents = answerContents; mAnswerType = answerType; mFillIntoEdit = TextUtils.isEmpty(fillIntoEdit) ? text : fillIntoEdit; mUrl = url; mFormattedUrl = formattedUrl; mIsStarred = isStarred; mIsDeletable = isDeletable; if (!TextUtils.isEmpty(mAnswerContents)) { // If any errors are encountered parsing the answer contents, this will return null and // hasAnswer will return false, just as if there were no answer contents at all. mAnswer = SuggestionAnswer.parseAnswerContents(mAnswerContents); } else { mAnswer = null; } } /* TODO(groby): Remove - see http://crbug.com/375482 */ public OmniboxSuggestion(int nativeType, int relevance, int transition, String text, String description, String fillIntoEdit, String url, String formattedUrl, boolean isStarred, boolean isDeletable) { this(nativeType, relevance, transition, text, description, null, null, fillIntoEdit, url, formattedUrl, isStarred, isDeletable); } public Type getType() { return mType; } public int getTransition() { return mTransition; } public String getDisplayText() { return mDisplayText; } public String getDescription() { return mDescription; } public String getAnswerContents() { return mAnswerContents; } public String getAnswerType() { return mAnswerType; } public SuggestionAnswer getAnswer() { return mAnswer; } public boolean hasAnswer() { return mAnswer != null; } public String getFillIntoEdit() { return mFillIntoEdit; } public String getUrl() { return mUrl; } public String getFormattedUrl() { return mFormattedUrl; } public boolean isUrlSuggestion() { return mType.isUrl(); } /** * @return Whether this suggestion represents a starred/bookmarked URL. */ public boolean isStarred() { return mIsStarred; } public boolean isDeletable() { return mIsDeletable; } /** * @return The relevance score of this suggestion. */ public int getRelevance() { return mRelevance; } @Override public String toString() { return mType + " relevance=" + mRelevance + " \"" + mDisplayText + "\" -> " + mUrl; } @Override public int hashCode() { int hash = 37 * mType.mNativeType + mDisplayText.hashCode() + mFillIntoEdit.hashCode() + (mIsStarred ? 1 : 0) + (mIsDeletable ? 1 : 0); if (mAnswerContents != null) { hash = hash + mAnswerContents.hashCode(); } return hash; } @Override public boolean equals(Object obj) { if (!(obj instanceof OmniboxSuggestion)) { return false; } OmniboxSuggestion suggestion = (OmniboxSuggestion) obj; boolean answersAreEqual = (mAnswerContents == null && suggestion.mAnswerContents == null) || (mAnswerContents != null && suggestion.mAnswerContents != null && mAnswerContents.equals(suggestion.mAnswerContents)); return mType == suggestion.mType && mFillIntoEdit.equals(suggestion.mFillIntoEdit) && mDisplayText.equals(suggestion.mDisplayText) && answersAreEqual && mIsStarred == suggestion.mIsStarred && mIsDeletable == suggestion.mIsDeletable; } }