Commit 4a2d7de6 authored by Matthew Jones's avatar Matthew Jones Committed by Commit Bot

Add ability to add custom views to omnibox suggestions

This patch adds the infrastructure to allow the omnibox suggestion
list to support custom view types. A view type is registered with the
adapter and the mediator is responsible for specifying the type of
view to be displayed.

Bug:909779

Change-Id: I2e3e6905fbf7e44d991c536134511e311078d1db
Reviewed-on: https://chromium-review.googlesource.com/c/1340947
Commit-Queue: Matthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarTheresa <twellington@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611763}
parent 9ea6b5a6
......@@ -48,6 +48,13 @@ class ContextualSuggestionsModel
PropertyKey.MENU_BUTTON_DELEGATE, PropertyKey.TITLE);
}
@Override
public Collection<PropertyKey> getAllProperties() {
return Arrays.asList(PropertyKey.CLOSE_BUTTON_ON_CLICK_LISTENER,
PropertyKey.MENU_BUTTON_DELEGATE, PropertyKey.TITLE,
PropertyKey.TOOLBAR_SHADOW_VISIBILITY);
}
/** @param clusters The current list of clusters. */
void setClusterList(List<ContextualSuggestionsCluster> clusters) {
mClusterList.setClusters(clusters);
......
......@@ -83,6 +83,15 @@ public class PropertyModel extends PropertyObservable<PropertyKey> {
this(buildData(keys));
}
/**
* Constructs a model with a generic collection of existing keys.
*
* @param keys The key types supported by this model.
*/
public PropertyModel(Collection<PropertyKey> keys) {
this(buildData(keys.toArray(new PropertyKey[keys.size()])));
}
private PropertyModel(Map<PropertyKey, ValueContainer> startingValues) {
mData = startingValues;
}
......@@ -209,6 +218,15 @@ public class PropertyModel extends PropertyObservable<PropertyKey> {
return properties;
}
@Override
public Collection<PropertyKey> getAllProperties() {
List<PropertyKey> properties = new ArrayList<>();
for (Map.Entry<PropertyKey, ValueContainer> entry : mData.entrySet()) {
properties.add(entry.getKey());
}
return properties;
}
/**
* Allows constructing a new {@link PropertyModel} with read-only properties.
*/
......
......@@ -52,6 +52,12 @@ public abstract class PropertyObservable<T> {
*/
public abstract Collection<T> getAllSetProperties();
/**
* @return A collection of all properties of this model. The returned collection should not be
* modified.
*/
public abstract Collection<T> getAllProperties();
/**
* Notifies observers that the property identified by {@code propertyKey} has changed.
*
......
......@@ -316,4 +316,9 @@ public class SnippetArticle
public Collection<PartialBindCallback> getAllSetProperties() {
return Collections.emptyList();
}
@Override
public Collection<PartialBindCallback> getAllProperties() {
return Collections.emptyList();
}
}
......@@ -146,6 +146,12 @@ public class AutocompleteCoordinator implements UrlFocusChangeListener, UrlTextC
list.setAdapter(adapter);
list.setClipToPadding(false);
// Register a view type for a default omnibox suggestion.
adapter.registerType(
OmniboxSuggestionUiType.DEFAULT,
() -> new SuggestionView(mListView.getContext()),
SuggestionViewViewBinder::bind);
mHolder = new SuggestionListViewHolder(container, list, adapter);
for (int i = 0; i < mCallbacks.size(); i++) {
......
......@@ -167,8 +167,10 @@ class AutocompleteMediator implements OnSuggestionsReceivedListener {
private void notifyPropertyModelsChanged() {
if (mPreventSuggestionListPropertyChanges) return;
List<PropertyModel> models = new ArrayList<>(mCurrentModels.size());
for (int i = 0; i < mCurrentModels.size(); i++) models.add(mCurrentModels.get(i).second);
List<Pair<Integer, PropertyModel>> models = new ArrayList<>(mCurrentModels.size());
for (int i = 0; i < mCurrentModels.size(); i++) {
models.add(new Pair<>(OmniboxSuggestionUiType.DEFAULT, mCurrentModels.get(i).second));
}
mListPropertyModel.set(SuggestionListProperties.SUGGESTION_MODELS, models);
}
......
......@@ -5,6 +5,8 @@
package org.chromium.chrome.browser.omnibox.suggestions;
import android.content.Context;
import android.util.Pair;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
......@@ -18,6 +20,7 @@ import org.chromium.chrome.browser.modelutil.PropertyModel.WritableFloatProperty
import org.chromium.chrome.browser.modelutil.PropertyModel.WritableIntPropertyKey;
import org.chromium.chrome.browser.modelutil.PropertyModel.WritableObjectPropertyKey;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor.ViewBinder;
import org.chromium.chrome.browser.omnibox.suggestions.SuggestionViewProperties.SuggestionIcon;
import java.util.ArrayList;
......@@ -28,8 +31,20 @@ import java.util.List;
*/
@VisibleForTesting
public class OmniboxResultsAdapter extends BaseAdapter {
/**
* An interface to provide a means to build specific view types.
* @param <T> The type of view that the implementor will build.
*/
public interface ViewBuilder<T extends View> {
/**
* @return A new view to show in the list.
*/
T buildView();
}
private final Context mContext;
private final List<PropertyModel> mSuggestionItems = new ArrayList<>();
private final List<Pair<Integer, PropertyModel>> mSuggestionItems = new ArrayList<>();
private final SparseArray<Pair<ViewBuilder, ViewBinder>> mViewBuilderMap = new SparseArray<>();
public OmniboxResultsAdapter(Context context) {
mContext = context;
......@@ -38,7 +53,7 @@ public class OmniboxResultsAdapter extends BaseAdapter {
/**
* Update the visible omnibox suggestions.
*/
public void updateSuggestions(List<PropertyModel> suggestionModels) {
public void updateSuggestions(List<Pair<Integer, PropertyModel>> suggestionModels) {
mSuggestionItems.clear();
mSuggestionItems.addAll(suggestionModels);
notifyDataSetChanged();
......@@ -59,17 +74,40 @@ public class OmniboxResultsAdapter extends BaseAdapter {
return position;
}
/**
* Register a new view type that this adapter knows how to show.
* @param typeId The ID of the view type. This should not match any other view type registered
* in this adapter.
* @param builder A mechanism for building new views of the specified type.
* @param binder A means of binding a model to the provided view.
*/
public <T extends View> void registerType(
int typeId, ViewBuilder<T> builder, ViewBinder<PropertyModel, T, PropertyKey> binder) {
assert mViewBuilderMap.valueAt(typeId) == null;
mViewBuilderMap.put(typeId, new Pair<>(builder, binder));
}
@Override
public int getItemViewType(int position) {
return mSuggestionItems.get(position).first;
}
@Override
public int getViewTypeCount() {
return Math.max(1, mViewBuilderMap.size());
}
@SuppressWarnings("unchecked")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SuggestionView suggestionView;
if (convertView instanceof SuggestionView) {
suggestionView = (SuggestionView) convertView;
} else {
suggestionView = new SuggestionView(mContext);
if (convertView == null) {
int suggestionTypeId = mSuggestionItems.get(position).first;
convertView = mViewBuilderMap.get(suggestionTypeId).first.buildView();
}
PropertyModel suggestionModel = mSuggestionItems.get(position);
PropertyModel viewModel = getModel(suggestionView);
PropertyModel suggestionModel = mSuggestionItems.get(position).second;
PropertyModel viewModel =
getOrCreateModelFromExisting(convertView, mSuggestionItems.get(position));
for (PropertyKey key : suggestionModel.getAllSetProperties()) {
if (key instanceof WritableIntPropertyKey) {
WritableIntPropertyKey intKey = (WritableIntPropertyKey) key;
......@@ -89,16 +127,19 @@ public class OmniboxResultsAdapter extends BaseAdapter {
}
}
// TODO(tedchoc): Investigate whether this is still needed.
suggestionView.jumpDrawablesToCurrentState();
convertView.jumpDrawablesToCurrentState();
return suggestionView;
return convertView;
}
private PropertyModel getModel(SuggestionView view) {
@SuppressWarnings("unchecked")
private PropertyModel getOrCreateModelFromExisting(
View view, Pair<Integer, PropertyModel> item) {
PropertyModel model = (PropertyModel) view.getTag(R.id.view_model);
if (model == null) {
model = new PropertyModel(SuggestionViewProperties.ALL_KEYS);
PropertyModelChangeProcessor.create(model, view, SuggestionViewViewBinder::bind);
model = new PropertyModel(item.second.getAllProperties());
PropertyModelChangeProcessor.create(
model, view, mViewBuilderMap.get(item.first).second);
model.set(SuggestionViewProperties.SUGGESTION_ICON_TYPE, SuggestionIcon.UNDEFINED);
view.setTag(R.id.view_model, model);
}
......
// 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.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** The different types of view that a suggestion can be. */
@IntDef({OmniboxSuggestionUiType.DEFAULT})
@Retention(RetentionPolicy.SOURCE)
@interface OmniboxSuggestionUiType {
int DEFAULT = 0;
}
......@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.omnibox.suggestions;
import android.util.Pair;
import org.chromium.chrome.browser.modelutil.PropertyKey;
import org.chromium.chrome.browser.modelutil.PropertyModel;
import org.chromium.chrome.browser.modelutil.PropertyModel.WritableBooleanPropertyKey;
......@@ -24,8 +26,8 @@ public class SuggestionListProperties {
new WritableObjectPropertyKey<>();
/** The list of models controlling the state of the suggestion items. */
public static final WritableObjectPropertyKey<List<PropertyModel>> SUGGESTION_MODELS =
new WritableObjectPropertyKey<>(true);
public static final WritableObjectPropertyKey<List<Pair<Integer, PropertyModel>>>
SUGGESTION_MODELS = new WritableObjectPropertyKey<>(true);
/** Whether the suggestion list should have a dark background. */
public static final WritableBooleanPropertyKey USE_DARK_BACKGROUND =
......
......@@ -1134,6 +1134,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxResultsAdapter.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestion.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionUiType.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsList.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListProperties.java",
"java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListViewBinder.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