// Copyright 2018 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.components.omnibox;
import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
import androidx.core.util.ObjectsCompat;
import org.jni_zero.CalledByNative;
import org.chromium.components.omnibox.AnswerTypeProto.AnswerType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** Contains the data needed to renderer a answer in the Omnibox suggestions. */
public class SuggestionAnswer {
private final AnswerType mType;
private final ImageLine mFirstLine;
private final ImageLine mSecondLine;
@VisibleForTesting
public SuggestionAnswer(AnswerType type, ImageLine firstLine, ImageLine secondLine) {
mType = type;
mFirstLine = firstLine;
mSecondLine = secondLine;
}
/** Return the type of Answer being shown. */
public AnswerType getType() {
return mType;
}
/** Returns the first of the two required image lines. */
public ImageLine getFirstLine() {
return mFirstLine;
}
/** Returns the second of the two required image lines. */
public ImageLine getSecondLine() {
return mSecondLine;
}
@Override
public int hashCode() {
// TODO(tedchoc): Replace usage of Arrays.hashCode with ObjectsCompat.hash once the support
// library is rolled past 27.1.
return Arrays.hashCode(new Object[] {mType, mFirstLine, mSecondLine});
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SuggestionAnswer)) return false;
SuggestionAnswer other = (SuggestionAnswer) obj;
return mType == other.mType
&& ObjectsCompat.equals(mFirstLine, other.mFirstLine)
&& ObjectsCompat.equals(mSecondLine, other.mSecondLine);
}
/**
* Represents a single line of an answer, containing any number of typed text fields and an
* optional image.
*/
public static class ImageLine {
private final List<TextField> mTextFields;
private final TextField mAdditionalText;
private final TextField mStatusText;
private final String mImage;
@VisibleForTesting
public ImageLine(
List<TextField> textFields,
TextField additionalText,
TextField statusText,
String imageUrl) {
mTextFields = textFields;
mAdditionalText = additionalText;
mStatusText = statusText;
mImage = imageUrl;
}
/** Return an unnamed list of text fields. These represent the main content of the line. */
public List<TextField> getTextFields() {
return mTextFields;
}
/** Returns true if the line contains an "additional text" field. */
public boolean hasAdditionalText() {
return mAdditionalText != null;
}
/** Return the "additional text" field. */
public TextField getAdditionalText() {
return mAdditionalText;
}
/** Returns true if the line contains an "status text" field. */
public boolean hasStatusText() {
return mStatusText != null;
}
/** Return the "status text" field. */
public TextField getStatusText() {
return mStatusText;
}
/** Returns true if the line contains an image. */
public boolean hasImage() {
return mImage != null;
}
/** Return the optional image (URL or base64-encoded image data). */
public String getImage() {
return mImage;
}
@Override
public int hashCode() {
return Arrays.deepHashCode(
new Object[] {mTextFields.toArray(), mAdditionalText, mStatusText, mImage});
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ImageLine)) return false;
ImageLine other = (ImageLine) obj;
if (mTextFields.size() != other.mTextFields.size()) return false;
for (int i = 0; i < mTextFields.size(); i++) {
if (!ObjectsCompat.equals(mTextFields.get(i), other.mTextFields.get(i))) {
return false;
}
}
return TextUtils.equals(mImage, other.mImage)
&& ObjectsCompat.equals(mAdditionalText, other.mAdditionalText)
&& ObjectsCompat.equals(mStatusText, other.mStatusText);
}
}
/** Represents one text field of an answer, containing a integer type and a string. */
public static class TextField {
@AnswerTextType private final int mType;
private final String mText;
@AnswerTextStyle private final int mStyle;
private final int mNumLines;
@VisibleForTesting
public TextField(
@AnswerTextType int type, String text, @AnswerTextStyle int style, int numLines) {
mType = type;
mText = text;
mStyle = style;
mNumLines = numLines;
}
@AnswerTextType
public int getType() {
return mType;
}
public String getText() {
return mText;
}
@AnswerTextStyle
public int getStyle() {
return mStyle;
}
public boolean hasNumLines() {
return mNumLines != -1;
}
public int getNumLines() {
return mNumLines;
}
@Override
public int hashCode() {
return Arrays.hashCode(new Object[] {mType, mText, mStyle, mNumLines});
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof TextField)) return false;
TextField other = (TextField) obj;
return mType == other.mType
&& TextUtils.equals(mText, other.mText)
&& mStyle == other.mStyle
&& mNumLines == other.mNumLines;
}
}
@CalledByNative
private static SuggestionAnswer createSuggestionAnswer(
int type, ImageLine firstLine, ImageLine secondLine) {
return new SuggestionAnswer(AnswerType.forNumber(type), firstLine, secondLine);
}
@CalledByNative
private static ImageLine createImageLine(
List<TextField> fields,
TextField additionalText,
TextField statusText,
String imageUrl) {
return new ImageLine(fields, additionalText, statusText, imageUrl);
}
@CalledByNative
private static List<TextField> createTextFieldList() {
return new ArrayList<>();
}
@CalledByNative
private static void addTextFieldToList(List<TextField> list, TextField field) {
list.add(field);
}
@CalledByNative
private static TextField createTextField(
@AnswerTextType int type, String text, @AnswerTextStyle int style, int numLines) {
return new TextField(type, text, style, numLines);
}
}