Commit a9bdbe5c authored by Shakti Sahu's avatar Shakti Sahu Committed by Commit Bot

Query Tiles: UI fixes

This CL fixes
1 - If we get redundant calls to the TileSuggestionProcessor, ignore them
and don't update the underlying widget. This will prevent the previous
suggestion from flashing up momementarily before new tile set is loaded.
2 - Default ItemAnimator is removed to prevent the jank
3 - Only reload the tile if NTP is reloaded via home button. For regular
page load, don't animate query tiles (fixes submit query flow jank)
4 - Fix for international languages - ASCII comparison is not enough
for non-english languages. string16 is used for comparison purposes,
which fixes the omnibox flow for query tiles (Bug 1086672)

Bug : 1086672, 1081557

Change-Id: I8536759fb3f7a9c9c00ddb56f5c12f40df26a114
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2211661
Commit-Queue: Shakti Sahu <shaktisahu@chromium.org>
Reviewed-by: default avatarTommy Li <tommycli@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772080}
parent ac1e32be
...@@ -3077,6 +3077,7 @@ native_java_unittests_tests = [ ...@@ -3077,6 +3077,7 @@ native_java_unittests_tests = [
"native_java_unittests/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessorUnitTest.java", "native_java_unittests/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessorUnitTest.java",
"native_java_unittests/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionUnitTest.java", "native_java_unittests/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionUnitTest.java",
"native_java_unittests/src/org/chromium/chrome/browser/omnibox/suggestions/entity/EntitySuggestionProcessorUnitTest.java", "native_java_unittests/src/org/chromium/chrome/browser/omnibox/suggestions/entity/EntitySuggestionProcessorUnitTest.java",
"native_java_unittests/src/org/chromium/chrome/browser/omnibox/suggestions/tiles/TileSuggestionProcessorUnitTest.java",
"native_java_unittests/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManagerUnitTest.java", "native_java_unittests/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManagerUnitTest.java",
"native_java_unittests/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java", "native_java_unittests/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java",
"native_java_unittests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java", "native_java_unittests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java",
...@@ -3111,6 +3112,7 @@ android_library("native_java_unittests_java") { ...@@ -3111,6 +3112,7 @@ android_library("native_java_unittests_java") {
"//components/omnibox/browser:browser_java", "//components/omnibox/browser:browser_java",
"//components/payments/content/android:java", "//components/payments/content/android:java",
"//components/payments/mojom:mojom_java", "//components/payments/mojom:mojom_java",
"//components/query_tiles:java",
"//components/search_engines/android:java", "//components/search_engines/android:java",
"//components/security_state/content/android:java", "//components/security_state/content/android:java",
"//components/security_state/core:security_state_enums_java", "//components/security_state/core:security_state_enums_java",
......
...@@ -346,7 +346,7 @@ public class NewTabPage implements NativePage, InvalidationAwareThumbnailProvide ...@@ -346,7 +346,7 @@ public class NewTabPage implements NativePage, InvalidationAwareThumbnailProvide
@Override @Override
public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) { public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
mNewTabPageLayout.onLoadUrl(); mNewTabPageLayout.onLoadUrl(isNTPUrl(tab.getUrl()));
} }
}; };
mTab.addObserver(mTabObserver); mTab.addObserver(mTabObserver);
......
...@@ -605,8 +605,8 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer ...@@ -605,8 +605,8 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
if (mQueryTileSection != null) mQueryTileSection.onUrlFocusAnimationChanged(percent); if (mQueryTileSection != null) mQueryTileSection.onUrlFocusAnimationChanged(percent);
} }
void onLoadUrl() { void onLoadUrl(boolean isNtpUrl) {
if (mQueryTileSection != null) mQueryTileSection.reloadTiles(); if (isNtpUrl && mQueryTileSection != null) mQueryTileSection.reloadTiles();
} }
/** /**
......
...@@ -14,10 +14,12 @@ import org.chromium.chrome.browser.omnibox.suggestions.SuggestionProcessor; ...@@ -14,10 +14,12 @@ import org.chromium.chrome.browser.omnibox.suggestions.SuggestionProcessor;
import org.chromium.components.query_tiles.QueryTile; import org.chromium.components.query_tiles.QueryTile;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** A class that handles model and view creation for the query tile suggestions. */ /** A class that handles model and view creation for the query tile suggestions. */
public class TileSuggestionProcessor implements SuggestionProcessor { public class TileSuggestionProcessor implements SuggestionProcessor {
private List<QueryTile> mLastProcessedTiles;
private final Callback<List<QueryTile>> mQueryTileSuggestionCallback; private final Callback<List<QueryTile>> mQueryTileSuggestionCallback;
private final int mMinViewHeight; private final int mMinViewHeight;
...@@ -49,7 +51,13 @@ public class TileSuggestionProcessor implements SuggestionProcessor { ...@@ -49,7 +51,13 @@ public class TileSuggestionProcessor implements SuggestionProcessor {
} }
@Override @Override
public void onUrlFocusChange(boolean hasFocus) {} public void onUrlFocusChange(boolean hasFocus) {
if (hasFocus) return;
// Clear out any old UI state for this processor.
mLastProcessedTiles = null;
mQueryTileSuggestionCallback.onResult(new ArrayList<>());
}
@Override @Override
public void onNativeInitialized() {} public void onNativeInitialized() {}
...@@ -61,7 +69,11 @@ public class TileSuggestionProcessor implements SuggestionProcessor { ...@@ -61,7 +69,11 @@ public class TileSuggestionProcessor implements SuggestionProcessor {
@Override @Override
public void populateModel(OmniboxSuggestion suggestion, PropertyModel model, int position) { public void populateModel(OmniboxSuggestion suggestion, PropertyModel model, int position) {
mQueryTileSuggestionCallback.onResult(suggestion.getQueryTiles()); List<QueryTile> tiles = suggestion.getQueryTiles();
if (mLastProcessedTiles != null && mLastProcessedTiles.equals(tiles)) return;
mLastProcessedTiles = new ArrayList<>(tiles);
mQueryTileSuggestionCallback.onResult(tiles);
} }
@Override @Override
......
...@@ -200,6 +200,6 @@ public class QueryTileSection { ...@@ -200,6 +200,6 @@ public class QueryTileSection {
return ChromeFeatureList.getFieldTrialParamByFeatureAsInt(ChromeFeatureList.QUERY_TILES, return ChromeFeatureList.getFieldTrialParamByFeatureAsInt(ChromeFeatureList.QUERY_TILES,
isSmallScreen ? MOST_VISITED_MAX_ROWS_SMALL_SCREEN isSmallScreen ? MOST_VISITED_MAX_ROWS_SMALL_SCREEN
: MOST_VISITED_MAX_ROWS_NORMAL_SCREEN, : MOST_VISITED_MAX_ROWS_NORMAL_SCREEN,
2); 1);
} }
} }
// Copyright 2020 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.tiles;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import org.junit.Assert;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.chromium.base.Callback;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.CalledByNativeJavaTest;
import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion;
import org.chromium.components.query_tiles.QueryTile;
import org.chromium.ui.modelutil.PropertyModel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Unit tests for the "query tiles" omnibox suggestion.
*/
public final class TileSuggestionProcessorUnitTest {
private PropertyModel mModel;
private TileSuggestionProcessor mProcessor;
@Mock
Context mContext;
@Mock
Resources mResources;
@Mock
Callback<List<QueryTile>> mSuggestionCallback;
@Mock
OmniboxSuggestion mSuggestion;
@CalledByNative
private TileSuggestionProcessorUnitTest() {}
@CalledByNative
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getResources()).thenReturn(mResources);
mModel = new PropertyModel();
mProcessor = new TileSuggestionProcessor(mContext, mSuggestionCallback);
}
@CalledByNativeJavaTest
public void testDuplicatesDoNotPropagateToUi() {
List<QueryTile> tiles = Arrays.asList(buildTile("1"), buildTile("2"));
List<QueryTile> tilesSameRef = new ArrayList<>(tiles);
List<QueryTile> tilesSameVal = Arrays.asList(buildTile("1"), buildTile("2"));
List<QueryTile> tilesDifferent = Arrays.asList(buildTile("3"));
when(mSuggestion.getQueryTiles())
.thenReturn(tiles, tilesSameRef, tilesSameVal, tilesDifferent, tilesDifferent);
mProcessor.populateModel(mSuggestion, mModel, 0);
mProcessor.populateModel(mSuggestion, mModel, 0);
mProcessor.populateModel(mSuggestion, mModel, 0);
mProcessor.populateModel(mSuggestion, mModel, 0);
mProcessor.onUrlFocusChange(false);
mProcessor.populateModel(mSuggestion, mModel, 0);
ArgumentCaptor<List<QueryTile>> captor = ArgumentCaptor.forClass(List.class);
verify(mSuggestionCallback, times(4)).onResult(captor.capture());
List<List<QueryTile>> results = captor.getAllValues();
Assert.assertEquals(tiles, results.get(0));
Assert.assertEquals(tilesDifferent, results.get(1));
Assert.assertEquals(new ArrayList<>(), results.get(2));
Assert.assertEquals(tilesDifferent, results.get(3));
}
private static QueryTile buildTile(String suffix) {
return new QueryTile("id" + suffix, "displayTitle" + suffix, "accessibilityText" + suffix,
"queryText" + suffix, new String[] {"url" + suffix}, new String[] {},
new ArrayList<>());
}
}
// Copyright 2020 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.
#include "base/android/jni_android.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/android/native_j_unittests_jni_headers/TileSuggestionProcessorUnitTest_jni.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::android::AttachCurrentThread;
class TileSuggestionProcessorUnitTest : public ::testing::Test {
public:
TileSuggestionProcessorUnitTest()
: j_test_(Java_TileSuggestionProcessorUnitTest_Constructor(
AttachCurrentThread())) {}
void SetUp() override {
Java_TileSuggestionProcessorUnitTest_setUp(AttachCurrentThread(), j_test_);
}
const base::android::ScopedJavaGlobalRef<jobject>& j_test() {
return j_test_;
}
private:
base::android::ScopedJavaGlobalRef<jobject> j_test_;
};
JAVA_TESTS(TileSuggestionProcessorUnitTest, j_test())
...@@ -3859,6 +3859,7 @@ test("unit_tests") { ...@@ -3859,6 +3859,7 @@ test("unit_tests") {
"../browser/omnibox/suggestions/clipboard/clipboard_suggestion_processor_unittest.cc", "../browser/omnibox/suggestions/clipboard/clipboard_suggestion_processor_unittest.cc",
"../browser/omnibox/suggestions/editurl/edit_url_suggestions_unittest.cc", "../browser/omnibox/suggestions/editurl/edit_url_suggestions_unittest.cc",
"../browser/omnibox/suggestions/entity/entity_suggestions_processor_unittest.cc", "../browser/omnibox/suggestions/entity/entity_suggestions_processor_unittest.cc",
"../browser/omnibox/suggestions/tiles/tile_suggestion_processor_unittest.cc",
"../browser/optimization_guide/android/optimization_guide_bridge_unittest.cc", "../browser/optimization_guide/android/optimization_guide_bridge_unittest.cc",
"../browser/page_load_metrics/observers/android_page_load_metrics_observer_unittest.cc", "../browser/page_load_metrics/observers/android_page_load_metrics_observer_unittest.cc",
"../browser/partnercustomizations/partner_browser_customizations_unittest.cc", "../browser/partnercustomizations/partner_browser_customizations_unittest.cc",
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
package org.chromium.components.browser_ui.widget.image_tiles; package org.chromium.components.browser_ui.widget.image_tiles;
import android.text.TextUtils;
import androidx.annotation.Nullable;
/** /**
* Class encapsulating data needed to render a image tile. An {@link ImageTile} is a tile meant to * Class encapsulating data needed to render a image tile. An {@link ImageTile} is a tile meant to
* show an image with some text. * show an image with some text.
...@@ -24,4 +28,12 @@ public class ImageTile { ...@@ -24,4 +28,12 @@ public class ImageTile {
this.displayTitle = displayTitle; this.displayTitle = displayTitle;
this.accessibilityText = accessibilityText; this.accessibilityText = accessibilityText;
} }
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof ImageTile)) return false;
ImageTile other = (ImageTile) obj;
return TextUtils.equals(id, other.id) && TextUtils.equals(displayTitle, other.displayTitle)
&& TextUtils.equals(accessibilityText, other.accessibilityText);
}
} }
...@@ -53,6 +53,7 @@ class TileListView { ...@@ -53,6 +53,7 @@ class TileListView {
mLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false); mLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
mView.setLayoutManager(mLayoutManager); mView.setLayoutManager(mLayoutManager);
mView.addItemDecoration(new ItemDecorationImpl(context)); mView.addItemDecoration(new ItemDecorationImpl(context));
mView.setItemAnimator(null);
mView.setLayoutAnimation( mView.setLayoutAnimation(
AnimationUtils.loadLayoutAnimation(context, R.anim.image_grid_enter)); AnimationUtils.loadLayoutAnimation(context, R.anim.image_grid_enter));
......
...@@ -23,10 +23,10 @@ bool TextMatchesQueryTile(base::string16 input_text, ...@@ -23,10 +23,10 @@ bool TextMatchesQueryTile(base::string16 input_text,
base::Optional<query_tiles::Tile> tile) { base::Optional<query_tiles::Tile> tile) {
auto trimmed_input = auto trimmed_input =
base::TrimWhitespace(input_text, base::TrimPositions::TRIM_TRAILING); base::TrimWhitespace(input_text, base::TrimPositions::TRIM_TRAILING);
auto tile_text = tile.has_value() ? tile->query_text : ""; auto tile_text = base::UTF8ToUTF16(tile.has_value() ? tile->query_text : "");
auto trimmed_tile_text = auto trimmed_tile_text =
base::TrimWhitespaceASCII(tile_text, base::TrimPositions::TRIM_TRAILING); base::TrimWhitespace(tile_text, base::TrimPositions::TRIM_TRAILING);
return base::EqualsASCII(trimmed_input, trimmed_tile_text); return trimmed_input == trimmed_tile_text;
} }
// Helper function to determine if we are currently showing an URL and the // Helper function to determine if we are currently showing an URL and the
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
package org.chromium.components.query_tiles; package org.chromium.components.query_tiles;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import org.chromium.components.browser_ui.widget.image_tiles.ImageTile; import org.chromium.components.browser_ui.widget.image_tiles.ImageTile;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -38,4 +42,22 @@ public class QueryTile extends ImageTile { ...@@ -38,4 +42,22 @@ public class QueryTile extends ImageTile {
this.children = this.children =
Collections.unmodifiableList(children == null ? new ArrayList<>() : children); Collections.unmodifiableList(children == null ? new ArrayList<>() : children);
} }
@Override
public boolean equals(@Nullable Object obj) {
if (!super.equals(obj)) return false;
if (!(obj instanceof QueryTile)) return false;
QueryTile other = (QueryTile) obj;
if (!TextUtils.equals(queryText, other.queryText)) return false;
if (children != null && !children.equals(other.children)) return false;
if (children == null && other.children != null) return false;
if (urls != null && !urls.equals(other.urls)) return false;
if (urls == null && other.urls != null) return false;
return true;
}
} }
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