Commit 90d65da7 authored by Ted Choc's avatar Ted Choc Committed by Commit Bot

Pull out model and view binding from SuggestionView.

This moves the logic into the adapter.  Sets up the preliminary
APIs on the View itself to allow a binder to interact with it,
and slowly cleans up a few of the broken dependencies.

The uphill battle goes on.

BUG=898522

Change-Id: Ib8c8c00049a929af723003ad5533caf356c074f1
Reviewed-on: https://chromium-review.googlesource.com/c/1298171
Commit-Queue: Ted Choc <tedchoc@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#602947}
parent 987c04d3
......@@ -131,4 +131,5 @@
<item type="id" name="highlight_state" />
<item type="id" name="item_animator" />
<item type="id" name="highlight_color" />
<item type="id" name="view_model" />
</resources>
// Copyright 2018 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.suggestions;
import android.graphics.Bitmap;
import android.support.annotation.IntDef;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.style.UpdateAppearance;
import android.util.Pair;
import org.chromium.chrome.browser.modelutil.PropertyKey;
import org.chromium.chrome.browser.modelutil.PropertyModel.WritableBooleanPropertyKey;
import org.chromium.chrome.browser.modelutil.PropertyModel.WritableIntPropertyKey;
import org.chromium.chrome.browser.modelutil.PropertyModel.WritableObjectPropertyKey;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* The properties associated with rendering the suggestion view.
*/
class SuggestionViewProperties {
@IntDef({SuggestionIcon.UNDEFINED, SuggestionIcon.BOOKMARK, SuggestionIcon.HISTORY,
SuggestionIcon.GLOBE, SuggestionIcon.MAGNIFIER, SuggestionIcon.VOICE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuggestionIcon {
int UNDEFINED = -1;
int BOOKMARK = 0;
int HISTORY = 1;
int GLOBE = 2;
int MAGNIFIER = 3;
int VOICE = 4;
}
/**
* Container for suggestion text that prevents updates when the text/spans has not changed.
*/
static class SuggestionTextContainer {
public final Spannable text;
public SuggestionTextContainer(Spannable text) {
this.text = text;
}
@Override
public String toString() {
return "SuggestionTextContainer: " + (text == null ? "null" : text.toString());
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SuggestionTextContainer)) return false;
SuggestionTextContainer other = (SuggestionTextContainer) obj;
if (!TextUtils.equals(text, other.text)) return false;
if (text == null) return true;
UpdateAppearance[] thisSpans = text.getSpans(0, text.length(), UpdateAppearance.class);
UpdateAppearance[] otherSpans =
other.text.getSpans(0, other.text.length(), UpdateAppearance.class);
if (thisSpans.length != otherSpans.length) return false;
for (int i = 0; i < thisSpans.length; i++) {
UpdateAppearance thisSpan = thisSpans[i];
UpdateAppearance otherSpan = otherSpans[i];
if (!thisSpan.getClass().equals(otherSpan.getClass())) return false;
if (text.getSpanStart(thisSpan) != other.text.getSpanStart(otherSpan)
|| text.getSpanEnd(thisSpan) != other.text.getSpanEnd(otherSpan)
|| text.getSpanFlags(thisSpan) != other.text.getSpanFlags(otherSpan)) {
return false;
}
// TODO(tedchoc): This is a dangerous assumption. We should actually update all
// span types we use in suggestion text to implement .equals and
// ensure the internal styles (e.g. color used in a foreground span)
// is actually the same. This "seems" safe for now, but not
// particularly robust.
//
// Once that happens, share this logic with
// UrlBarMediator#isNewTextEquivalentToExistingText.
}
return true;
}
}
/** Whether dark colors should be applied to text, icons */
public static final WritableBooleanPropertyKey USE_DARK_COLORS =
new WritableBooleanPropertyKey();
/** Whether the suggestion is for an answer. */
public static final WritableBooleanPropertyKey IS_ANSWER = new WritableBooleanPropertyKey();
/** Whether an answer image will be shown. */
public static final WritableBooleanPropertyKey HAS_ANSWER_IMAGE =
new WritableBooleanPropertyKey();
/** The answer image to be shown. */
public static final WritableObjectPropertyKey<Bitmap> ANSWER_IMAGE =
new WritableObjectPropertyKey<>();
/** Whether the suggestion supports refinement. */
public static final WritableBooleanPropertyKey REFINABLE = new WritableBooleanPropertyKey();
/** The suggestion icon type shown. */
public static final WritableIntPropertyKey SUGGESTION_ICON_TYPE = new WritableIntPropertyKey();
/**
* The sizing information for the first line of text.
*
* The first item is the unit of size (e.g. TypedValue.COMPLEX_UNIT_PX), and the second item
* is the size itself.
*/
public static final WritableObjectPropertyKey<Pair<Integer, Float>> TEXT_LINE_1_SIZING =
new WritableObjectPropertyKey<>();
/** The actual text content for the first line of text. */
public static final WritableObjectPropertyKey<SuggestionTextContainer> TEXT_LINE_1_TEXT =
new WritableObjectPropertyKey<>();
/** The alignment constraints for positioning the first line of text. */
public static final WritableObjectPropertyKey<Pair<Float, Float>>
TEXT_LINE_1_ALIGNMENT_CONSTRAINTS = new WritableObjectPropertyKey<>();
/**
* The sizing information for the second line of text.
*
* The first item is the unit of size (e.g. TypedValue.COMPLEX_UNIT_PX), and the second item
* is the size itself.
*/
public static final WritableObjectPropertyKey<Pair<Integer, Float>> TEXT_LINE_2_SIZING =
new WritableObjectPropertyKey<>();
/** The maximum number of lines to be shown for the second line of text. */
public static final WritableIntPropertyKey TEXT_LINE_2_MAX_LINES = new WritableIntPropertyKey();
/** The color to be applied to the second line of text. */
public static final WritableIntPropertyKey TEXT_LINE_2_TEXT_COLOR =
new WritableIntPropertyKey();
/** The direction the text should be laid out for the second line of text. */
public static final WritableIntPropertyKey TEXT_LINE_2_TEXT_DIRECTION =
new WritableIntPropertyKey();
/** The actual text content for the second line of text. */
public static final WritableObjectPropertyKey<SuggestionTextContainer> TEXT_LINE_2_TEXT =
new WritableObjectPropertyKey<>();
public static final PropertyKey[] ALL_KEYS =
new PropertyKey[] {USE_DARK_COLORS, IS_ANSWER, HAS_ANSWER_IMAGE, ANSWER_IMAGE,
REFINABLE, SUGGESTION_ICON_TYPE, TEXT_LINE_1_SIZING, TEXT_LINE_1_TEXT,
TEXT_LINE_1_ALIGNMENT_CONSTRAINTS, TEXT_LINE_2_SIZING, TEXT_LINE_2_MAX_LINES,
TEXT_LINE_2_TEXT_COLOR, TEXT_LINE_2_TEXT_DIRECTION, TEXT_LINE_2_TEXT};
}
\ No newline at end of file
// Copyright 2018 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.suggestions;
import android.content.Context;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.text.Spannable;
import android.text.TextUtils;
import android.util.Pair;
import android.view.View;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.modelutil.PropertyKey;
import org.chromium.chrome.browser.modelutil.PropertyModel;
import org.chromium.chrome.browser.omnibox.suggestions.SuggestionViewProperties.SuggestionIcon;
import org.chromium.ui.base.DeviceFormFactor;
class SuggestionViewViewBinder {
/**
* @see
* org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor.ViewBinder#bind(Object,
* Object, Object)
*/
public static void bind(PropertyModel model, SuggestionView view, PropertyKey propertyKey) {
if (SuggestionViewProperties.USE_DARK_COLORS.equals(propertyKey)) {
boolean useDarkColors = model.get(SuggestionViewProperties.USE_DARK_COLORS);
view.updateRefineIconTint(useDarkColors);
view.updateSuggestionIconTint(useDarkColors);
view.getTextLine1().setTextColor(
getStandardFontColor(view.getContext(), useDarkColors));
} else if (SuggestionViewProperties.IS_ANSWER.equals(propertyKey)) {
updateSuggestionLayoutType(view, model);
} else if (SuggestionViewProperties.HAS_ANSWER_IMAGE.equals(propertyKey)) {
int visibility =
model.get(SuggestionViewProperties.HAS_ANSWER_IMAGE) ? View.VISIBLE : View.GONE;
view.getAnswerImageView().setVisibility(visibility);
} else if (SuggestionViewProperties.ANSWER_IMAGE.equals(propertyKey)) {
view.getAnswerImageView().setImageBitmap(
model.get(SuggestionViewProperties.ANSWER_IMAGE));
} else if (SuggestionViewProperties.REFINABLE.equals(propertyKey)) {
boolean refinable = model.get(SuggestionViewProperties.REFINABLE);
view.setRefinable(refinable);
if (refinable) view.initRefineIcon(model.get(SuggestionViewProperties.USE_DARK_COLORS));
} else if (SuggestionViewProperties.SUGGESTION_ICON_TYPE.equals(propertyKey)) {
if (!DeviceFormFactor.isNonMultiDisplayContextOnTablet(view.getContext())) return;
@SuggestionIcon
int type = model.get(SuggestionViewProperties.SUGGESTION_ICON_TYPE);
if (type == SuggestionIcon.UNDEFINED) return;
int drawableId = R.drawable.ic_omnibox_page;
switch (type) {
case SuggestionIcon.BOOKMARK:
drawableId = R.drawable.btn_star;
break;
case SuggestionIcon.MAGNIFIER:
drawableId = R.drawable.ic_suggestion_magnifier;
break;
case SuggestionIcon.HISTORY:
drawableId = R.drawable.ic_suggestion_history;
break;
case SuggestionIcon.VOICE:
drawableId = R.drawable.btn_mic;
break;
default:
break;
}
view.setSuggestionIconDrawable(
drawableId, model.get(SuggestionViewProperties.USE_DARK_COLORS));
} else if (SuggestionViewProperties.TEXT_LINE_1_SIZING.equals(propertyKey)) {
Pair<Integer, Float> sizing = model.get(SuggestionViewProperties.TEXT_LINE_1_SIZING);
view.getTextLine1().setTextSize(sizing.first, sizing.second);
} else if (SuggestionViewProperties.TEXT_LINE_1_TEXT.equals(propertyKey)) {
view.getTextLine1().setText(model.get(SuggestionViewProperties.TEXT_LINE_1_TEXT).text);
} else if (SuggestionViewProperties.TEXT_LINE_1_ALIGNMENT_CONSTRAINTS.equals(propertyKey)) {
Pair<Float, Float> constraints =
model.get(SuggestionViewProperties.TEXT_LINE_1_ALIGNMENT_CONSTRAINTS);
view.updateTextAlignmentConstraintWidths(constraints.first, constraints.second);
} else if (SuggestionViewProperties.TEXT_LINE_2_SIZING.equals(propertyKey)) {
Pair<Integer, Float> sizing = model.get(SuggestionViewProperties.TEXT_LINE_2_SIZING);
view.getTextLine2().setTextSize(sizing.first, sizing.second);
} else if (SuggestionViewProperties.TEXT_LINE_2_MAX_LINES.equals(propertyKey)) {
updateSuggestionLayoutType(view, model);
int numberLines = model.get(SuggestionViewProperties.TEXT_LINE_2_MAX_LINES);
if (numberLines == 1) {
view.getTextLine2().setEllipsize(null);
view.getTextLine2().setSingleLine();
} else {
view.getTextLine2().setSingleLine(false);
view.getTextLine2().setEllipsize(TextUtils.TruncateAt.END);
view.getTextLine2().setMaxLines(numberLines);
}
} else if (SuggestionViewProperties.TEXT_LINE_2_TEXT_COLOR.equals(propertyKey)) {
view.getTextLine2().setTextColor(
model.get(SuggestionViewProperties.TEXT_LINE_2_TEXT_COLOR));
} else if (SuggestionViewProperties.TEXT_LINE_2_TEXT_DIRECTION.equals(propertyKey)) {
ApiCompatibilityUtils.setTextDirection(view.getTextLine2(),
model.get(SuggestionViewProperties.TEXT_LINE_2_TEXT_DIRECTION));
} else if (SuggestionViewProperties.TEXT_LINE_2_TEXT.equals(propertyKey)) {
Spannable line2Text = model.get(SuggestionViewProperties.TEXT_LINE_2_TEXT).text;
if (TextUtils.isEmpty(line2Text)) {
view.getTextLine2().setVisibility(View.INVISIBLE);
} else {
view.getTextLine2().setVisibility(View.VISIBLE);
view.getTextLine2().setText(line2Text);
}
}
}
private static void updateSuggestionLayoutType(SuggestionView view, PropertyModel model) {
boolean isAnswer = model.get(SuggestionViewProperties.IS_ANSWER);
int numberLines = model.get(SuggestionViewProperties.TEXT_LINE_2_MAX_LINES);
if (!isAnswer) {
view.setSuggestionLayoutType(SuggestionView.SuggestionLayoutType.TEXT_SUGGESTION);
} else {
view.setSuggestionLayoutType(numberLines > 1
? SuggestionView.SuggestionLayoutType.MULTI_LINE_ANSWER
: SuggestionView.SuggestionLayoutType.ANSWER);
}
}
/**
* Get the appropriate font color to be used for non-URL text in suggestions.
* @param context The context to load the color.
* @param useDarkColors Whether dark colors should be used.
* @return The font color to be used.
*/
@ColorInt
public static int getStandardFontColor(Context context, boolean useDarkColors) {
@ColorRes
int res = useDarkColors ? R.color.url_emphasis_default_text
: R.color.url_emphasis_light_default_text;
return ApiCompatibilityUtils.getColor(context.getResources(), res);
}
/**
* Get the appropriate font color to be used for URL text in suggestions.
* @param context The context to load the color.
* @param useDarkColors Whether dark colors should be used.
* @return The font color to be used.
*/
@ColorInt
public static int getStandardUrlColor(Context context, boolean useDarkColors) {
@ColorRes
int res = useDarkColors ? R.color.suggestion_url_dark_modern
: R.color.suggestion_url_light_modern;
return ApiCompatibilityUtils.getColor(context.getResources(), res);
}
}
......@@ -1100,6 +1100,8 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsList.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionAnswer.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionView.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionViewProperties.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionViewViewBinder.java",
"java/src/org/chromium/chrome/browser/page_info/CertificateChainHelper.java",
"java/src/org/chromium/chrome/browser/page_info/CertificateViewer.java",
"java/src/org/chromium/chrome/browser/page_info/ConnectionInfoPopup.java",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment