Commit 52aea3d0 authored by Tomasz Wiszkowski's avatar Tomasz Wiszkowski Committed by Commit Bot

Allow BaseSuggestion to host arbitrary number of Action icons.

Change-Id: Iee930bac15483daaf0bb7a88ab48af0007717a7d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2219580
Commit-Queue: Ender <ender@google.com>
Reviewed-by: default avatarFilip Gorski <fgorski@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#773830}
parent 2e1adfe0
...@@ -21,6 +21,9 @@ import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDeleg ...@@ -21,6 +21,9 @@ import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDeleg
import org.chromium.chrome.browser.util.KeyNavigationUtil; import org.chromium.chrome.browser.util.KeyNavigationUtil;
import org.chromium.components.browser_ui.widget.RoundedCornerImageView; import org.chromium.components.browser_ui.widget.RoundedCornerImageView;
import java.util.ArrayList;
import java.util.List;
/** /**
* Base layout for common suggestion types. Includes support for a configurable suggestion content * Base layout for common suggestion types. Includes support for a configurable suggestion content
* and the common suggestion patterns shared across suggestion formats. * and the common suggestion patterns shared across suggestion formats.
...@@ -28,9 +31,9 @@ import org.chromium.components.browser_ui.widget.RoundedCornerImageView; ...@@ -28,9 +31,9 @@ import org.chromium.components.browser_ui.widget.RoundedCornerImageView;
* @param <T> The type of View being wrapped by this container. * @param <T> The type of View being wrapped by this container.
*/ */
public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutView { public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutView {
protected final ImageView mActionView; private final List<ImageView> mActionButtons;
protected final DecoratedSuggestionView<T> mDecoratedView; private final @DrawableRes int mSelectableBackgroundRes;
private final DecoratedSuggestionView<T> mDecoratedView;
private SuggestionViewDelegate mDelegate; private SuggestionViewDelegate mDelegate;
/** /**
...@@ -43,10 +46,9 @@ public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutVi ...@@ -43,10 +46,9 @@ public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutVi
TypedValue themeRes = new TypedValue(); TypedValue themeRes = new TypedValue();
getContext().getTheme().resolveAttribute(R.attr.selectableItemBackground, themeRes, true); getContext().getTheme().resolveAttribute(R.attr.selectableItemBackground, themeRes, true);
@DrawableRes mSelectableBackgroundRes = themeRes.resourceId;
int selectableBackgroundRes = themeRes.resourceId;
mDecoratedView = new DecoratedSuggestionView<>(getContext(), selectableBackgroundRes); mDecoratedView = new DecoratedSuggestionView<>(getContext(), mSelectableBackgroundRes);
mDecoratedView.setOnClickListener(v -> mDelegate.onSelection()); mDecoratedView.setOnClickListener(v -> mDelegate.onSelection());
mDecoratedView.setOnLongClickListener(v -> { mDecoratedView.setOnLongClickListener(v -> {
mDelegate.onLongPress(); mDelegate.onLongPress();
...@@ -55,23 +57,66 @@ public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutVi ...@@ -55,23 +57,66 @@ public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutVi
mDecoratedView.setLayoutParams(LayoutParams.forDynamicView()); mDecoratedView.setLayoutParams(LayoutParams.forDynamicView());
addView(mDecoratedView); addView(mDecoratedView);
// Action icons. Currently we only support the Refine button. mActionButtons = new ArrayList<>();
mActionView = new AppCompatImageView(getContext());
mActionView.setBackgroundResource(selectableBackgroundRes);
mActionView.setClickable(true);
mActionView.setFocusable(true);
mActionView.setScaleType(ImageView.ScaleType.CENTER);
mActionView.setContentDescription(
getResources().getString(R.string.accessibility_omnibox_btn_refine));
mActionView.setImageResource(R.drawable.btn_suggestion_refine);
mActionView.setLayoutParams(new LayoutParams(
getResources().getDimensionPixelSize(R.dimen.omnibox_suggestion_action_icon_width),
LayoutParams.MATCH_PARENT));
addView(mActionView);
setContentView(view); setContentView(view);
} }
/**
* Prepare (truncate or add) Action views for the Suggestion.
*
* @param desiredViewCount Number of action views for this suggestion.
*/
void setActionButtonsCount(int desiredViewCount) {
final int currentViewCount = mActionButtons.size();
if (currentViewCount < desiredViewCount) {
increaseActionButtonsCount(desiredViewCount);
} else if (currentViewCount > desiredViewCount) {
decreaseActionButtonsCount(desiredViewCount);
}
}
/**
* @return List of Action views.
*/
List<ImageView> getActionButtons() {
return mActionButtons;
}
/**
* Create additional action buttons for the suggestion view.
*
* @param desiredViewCount Desired number of action buttons.
*/
private void increaseActionButtonsCount(int desiredViewCount) {
for (int index = mActionButtons.size(); index < desiredViewCount; index++) {
ImageView actionView = new AppCompatImageView(getContext());
actionView.setBackgroundResource(mSelectableBackgroundRes);
actionView.setClickable(true);
actionView.setFocusable(true);
actionView.setScaleType(ImageView.ScaleType.CENTER);
actionView.setLayoutParams(
new LayoutParams(getResources().getDimensionPixelSize(
R.dimen.omnibox_suggestion_action_icon_width),
LayoutParams.MATCH_PARENT));
mActionButtons.add(actionView);
addView(actionView);
}
}
/**
* Remove unused action views from the suggestion view.
*
* @param desiredViewCount Desired target number of action buttons.
*/
private void decreaseActionButtonsCount(int desiredViewCount) {
for (int index = desiredViewCount; index < mActionButtons.size(); index++) {
removeView(mActionButtons.get(index));
}
mActionButtons.subList(desiredViewCount, mActionButtons.size()).clear();
}
/** /**
* Constructs a new suggestion view and inflates supplied layout as the contents view. * Constructs a new suggestion view and inflates supplied layout as the contents view.
* *
...@@ -99,7 +144,10 @@ public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutVi ...@@ -99,7 +144,10 @@ public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutVi
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
if ((!isRtl && KeyNavigationUtil.isGoRight(event)) if ((!isRtl && KeyNavigationUtil.isGoRight(event))
|| (isRtl && KeyNavigationUtil.isGoLeft(event))) { || (isRtl && KeyNavigationUtil.isGoLeft(event))) {
return mActionView.callOnClick(); // For views with exactly 1 action icon, continue to support the arrow key triggers.
if (mActionButtons.size() == 1) {
mActionButtons.get(0).callOnClick();
}
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
...@@ -144,9 +192,4 @@ public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutVi ...@@ -144,9 +192,4 @@ public class BaseSuggestionView<T extends View> extends SimpleHorizontalLayoutVi
RoundedCornerImageView getSuggestionImageView() { RoundedCornerImageView getSuggestionImageView() {
return mDecoratedView.getImageView(); return mDecoratedView.getImageView();
} }
/** @return Widget holding action icon. */
ImageView getActionImageView() {
return mActionView;
}
} }
...@@ -16,12 +16,15 @@ import androidx.core.view.ViewCompat; ...@@ -16,12 +16,15 @@ import androidx.core.view.ViewCompat;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.omnibox.suggestions.SuggestionCommonProperties; import org.chromium.chrome.browser.omnibox.suggestions.SuggestionCommonProperties;
import org.chromium.chrome.browser.omnibox.suggestions.base.BaseSuggestionViewProperties.Action;
import org.chromium.components.browser_ui.styles.ChromeColors; import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.browser_ui.widget.RoundedCornerImageView; import org.chromium.components.browser_ui.widget.RoundedCornerImageView;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder; import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder;
import java.util.List;
/** /**
* Binds base suggestion view properties. * Binds base suggestion view properties.
* *
...@@ -48,15 +51,6 @@ public final class BaseSuggestionViewBinder<T extends View> ...@@ -48,15 +51,6 @@ public final class BaseSuggestionViewBinder<T extends View>
} else if (BaseSuggestionViewProperties.ICON == propertyKey) { } else if (BaseSuggestionViewProperties.ICON == propertyKey) {
updateSuggestionIcon(model, view); updateSuggestionIcon(model, view);
updateContentViewPadding(model, view.getDecoratedSuggestionView()); updateContentViewPadding(model, view.getDecoratedSuggestionView());
} else if (BaseSuggestionViewProperties.ACTION_ICON == propertyKey) {
updateActionIcon(model, view);
} else if (BaseSuggestionViewProperties.ACTION_CALLBACK == propertyKey) {
final Runnable callback = model.get(BaseSuggestionViewProperties.ACTION_CALLBACK);
if (callback != null) {
view.getActionImageView().setOnClickListener(v -> callback.run());
} else {
view.getActionImageView().setOnClickListener(null);
}
} else if (BaseSuggestionViewProperties.DENSITY == propertyKey) { } else if (BaseSuggestionViewProperties.DENSITY == propertyKey) {
updateContentViewPadding(model, view.getDecoratedSuggestionView()); updateContentViewPadding(model, view.getDecoratedSuggestionView());
} else if (SuggestionCommonProperties.LAYOUT_DIRECTION == propertyKey) { } else if (SuggestionCommonProperties.LAYOUT_DIRECTION == propertyKey) {
...@@ -64,8 +58,39 @@ public final class BaseSuggestionViewBinder<T extends View> ...@@ -64,8 +58,39 @@ public final class BaseSuggestionViewBinder<T extends View>
view, model.get(SuggestionCommonProperties.LAYOUT_DIRECTION)); view, model.get(SuggestionCommonProperties.LAYOUT_DIRECTION));
updateContentViewPadding(model, view.getDecoratedSuggestionView()); updateContentViewPadding(model, view.getDecoratedSuggestionView());
} else if (SuggestionCommonProperties.USE_DARK_COLORS == propertyKey) { } else if (SuggestionCommonProperties.USE_DARK_COLORS == propertyKey) {
updateColorScheme(model, view);
} else if (BaseSuggestionViewProperties.ACTIONS == propertyKey) {
bindActionButtons(model, view, model.get(BaseSuggestionViewProperties.ACTIONS));
}
}
/** Bind Action Icons for the suggestion view. */
private static <T extends View> void bindActionButtons(
PropertyModel model, BaseSuggestionView<T> view, List<Action> actions) {
final int actionCount = actions != null ? actions.size() : 0;
view.setActionButtonsCount(actionCount);
final List<ImageView> actionViews = view.getActionButtons();
for (int index = 0; index < actionCount; index++) {
final ImageView actionView = actionViews.get(index);
final Action action = actions.get(index);
actionView.setOnClickListener(v -> action.callback.run());
actionView.setContentDescription(
view.getContext().getResources().getString(action.accessibilityDescription));
updateIcon(actionView, action.icon,
ChromeColors.getPrimaryIconTintRes(!isDarkMode(model)));
}
}
/** Update visual theme to reflect dark mode UI theme update. */
private static <T extends View> void updateColorScheme(
PropertyModel model, BaseSuggestionView<T> view) {
updateSuggestionIcon(model, view); updateSuggestionIcon(model, view);
updateActionIcon(model, view); final List<Action> actions = model.get(BaseSuggestionViewProperties.ACTIONS);
final List<ImageView> actionViews = view.getActionButtons();
for (int index = 0; index < actionViews.size(); index++) {
updateIcon(actionViews.get(index), actions.get(index).icon,
ChromeColors.getPrimaryIconTintRes(!isDarkMode(model)));
} }
} }
...@@ -106,14 +131,6 @@ public final class BaseSuggestionViewBinder<T extends View> ...@@ -106,14 +131,6 @@ public final class BaseSuggestionViewBinder<T extends View>
updateIcon(rciv, sds, ChromeColors.getSecondaryIconTintRes(!isDarkMode(model))); updateIcon(rciv, sds, ChromeColors.getSecondaryIconTintRes(!isDarkMode(model)));
} }
/** Update attributes of decorated suggestion icon. */
private static <T extends View> void updateActionIcon(
PropertyModel model, BaseSuggestionView<T> baseView) {
final ImageView view = baseView.getActionImageView();
final SuggestionDrawableState sds = model.get(BaseSuggestionViewProperties.ACTION_ICON);
updateIcon(view, sds, ChromeColors.getPrimaryIconTintRes(!isDarkMode(model)));
}
/** /**
* Update content view padding. * Update content view padding.
* This is required only to adjust the leading padding for undecorated suggestions. * This is required only to adjust the leading padding for undecorated suggestions.
......
...@@ -18,12 +18,14 @@ import org.chromium.chrome.browser.omnibox.MatchClassificationStyle; ...@@ -18,12 +18,14 @@ import org.chromium.chrome.browser.omnibox.MatchClassificationStyle;
import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion; import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion;
import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion.MatchClassification; import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion.MatchClassification;
import org.chromium.chrome.browser.omnibox.suggestions.SuggestionProcessor; import org.chromium.chrome.browser.omnibox.suggestions.SuggestionProcessor;
import org.chromium.chrome.browser.omnibox.suggestions.base.BaseSuggestionViewProperties.Action;
import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionHost; import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionHost;
import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDelegate; import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDelegate;
import org.chromium.chrome.browser.ui.favicon.LargeIconBridge; import org.chromium.chrome.browser.ui.favicon.LargeIconBridge;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.url.GURL; import org.chromium.url.GURL;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
...@@ -96,13 +98,10 @@ public abstract class BaseSuggestionViewProcessor implements SuggestionProcessor ...@@ -96,13 +98,10 @@ public abstract class BaseSuggestionViewProcessor implements SuggestionProcessor
* Specify SuggestionDrawableState for action button. * Specify SuggestionDrawableState for action button.
* *
* @param model Property model to update. * @param model Property model to update.
* @param drawable SuggestionDrawableState object defining decoration for the action button. * @param actions List of actions for the suggestion.
* @param callback Runnable to invoke when user presses the action icon.
*/ */
protected void setCustomAction( protected void setCustomActions(PropertyModel model, List<Action> actions) {
PropertyModel model, SuggestionDrawableState drawable, Runnable callback) { model.set(BaseSuggestionViewProperties.ACTIONS, actions);
model.set(BaseSuggestionViewProperties.ACTION_ICON, drawable);
model.set(BaseSuggestionViewProperties.ACTION_CALLBACK, callback);
} }
/** /**
...@@ -113,13 +112,15 @@ public abstract class BaseSuggestionViewProcessor implements SuggestionProcessor ...@@ -113,13 +112,15 @@ public abstract class BaseSuggestionViewProcessor implements SuggestionProcessor
* @param isSearchQuery Whether refineText is an URL or Search query. * @param isSearchQuery Whether refineText is an URL or Search query.
*/ */
protected void setRefineAction(PropertyModel model, OmniboxSuggestion suggestion) { protected void setRefineAction(PropertyModel model, OmniboxSuggestion suggestion) {
setCustomAction(model, setCustomActions(model,
Arrays.asList(new Action(
SuggestionDrawableState.Builder SuggestionDrawableState.Builder
.forDrawableRes(mContext, R.drawable.btn_suggestion_refine) .forDrawableRes(mContext, R.drawable.btn_suggestion_refine)
.setLarge(true) .setLarge(true)
.setAllowTint(true) .setAllowTint(true)
.build(), .build(),
() -> { mSuggestionHost.onRefineSuggestion(suggestion); }); R.string.accessibility_omnibox_btn_refine,
() -> mSuggestionHost.onRefineSuggestion(suggestion))));
} }
@Override @Override
...@@ -129,7 +130,7 @@ public abstract class BaseSuggestionViewProcessor implements SuggestionProcessor ...@@ -129,7 +130,7 @@ public abstract class BaseSuggestionViewProcessor implements SuggestionProcessor
model.set(BaseSuggestionViewProperties.SUGGESTION_DELEGATE, delegate); model.set(BaseSuggestionViewProperties.SUGGESTION_DELEGATE, delegate);
model.set(BaseSuggestionViewProperties.DENSITY, mDensity); model.set(BaseSuggestionViewProperties.DENSITY, mDensity);
setCustomAction(model, null, null); setCustomActions(model, null);
} }
/** /**
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.omnibox.suggestions.base; package org.chromium.chrome.browser.omnibox.suggestions.base;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.StringRes;
import org.chromium.chrome.browser.omnibox.suggestions.SuggestionCommonProperties; import org.chromium.chrome.browser.omnibox.suggestions.SuggestionCommonProperties;
import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDelegate; import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDelegate;
...@@ -15,6 +16,7 @@ import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; ...@@ -15,6 +16,7 @@ import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.List;
/** The base set of properties for most omnibox suggestions. */ /** The base set of properties for most omnibox suggestions. */
public class BaseSuggestionViewProperties { public class BaseSuggestionViewProperties {
...@@ -27,17 +29,35 @@ public class BaseSuggestionViewProperties { ...@@ -27,17 +29,35 @@ public class BaseSuggestionViewProperties {
int COMPACT = 2; int COMPACT = 2;
} }
/**
* Describes the content and behavior of the interactive Action Icon.
*/
public static final class Action {
public final SuggestionDrawableState icon;
public final Runnable callback;
public final @StringRes int accessibilityDescription;
/**
* Create a new action for suggestion.
*
* @param icon SuggestionDrawableState describing the icon to show.
* @param description Content description for the action view.
* @param callback Callback to invoke when user interacts with the icon.
*/
Action(SuggestionDrawableState icon, @StringRes int description, Runnable callback) {
this.icon = icon;
this.accessibilityDescription = description;
this.callback = callback;
}
}
/** SuggestionDrawableState to show as a suggestion icon. */ /** SuggestionDrawableState to show as a suggestion icon. */
public static final WritableObjectPropertyKey<SuggestionDrawableState> ICON = public static final WritableObjectPropertyKey<SuggestionDrawableState> ICON =
new WritableObjectPropertyKey<>(); new WritableObjectPropertyKey<>();
/** SuggestionDrawableState to show as an action icon. */ /** Action Icons description. */
public static final WritableObjectPropertyKey<SuggestionDrawableState> ACTION_ICON = public static final WritableObjectPropertyKey<List<Action>> ACTIONS =
new WritableObjectPropertyKey<>(); new WritableObjectPropertyKey();
/** ActionCallback to invoke when user presses the ActionIcon. */
public static final WritableObjectPropertyKey<Runnable> ACTION_CALLBACK =
new WritableObjectPropertyKey<>();
/** Delegate receiving user events. */ /** Delegate receiving user events. */
public static final WritableObjectPropertyKey<SuggestionViewDelegate> SUGGESTION_DELEGATE = public static final WritableObjectPropertyKey<SuggestionViewDelegate> SUGGESTION_DELEGATE =
...@@ -47,7 +67,7 @@ public class BaseSuggestionViewProperties { ...@@ -47,7 +67,7 @@ public class BaseSuggestionViewProperties {
public static final WritableIntPropertyKey DENSITY = new WritableIntPropertyKey(); public static final WritableIntPropertyKey DENSITY = new WritableIntPropertyKey();
public static final PropertyKey[] ALL_UNIQUE_KEYS = public static final PropertyKey[] ALL_UNIQUE_KEYS =
new PropertyKey[] {ICON, DENSITY, ACTION_ICON, ACTION_CALLBACK, SUGGESTION_DELEGATE}; new PropertyKey[] {ACTIONS, ICON, DENSITY, SUGGESTION_DELEGATE};
public static final PropertyKey[] ALL_KEYS = public static final PropertyKey[] ALL_KEYS =
PropertyModel.concatKeys(ALL_UNIQUE_KEYS, SuggestionCommonProperties.ALL_KEYS); PropertyModel.concatKeys(ALL_UNIQUE_KEYS, SuggestionCommonProperties.ALL_KEYS);
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
package org.chromium.chrome.browser.omnibox.suggestions.base; package org.chromium.chrome.browser.omnibox.suggestions.base;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
...@@ -22,7 +22,6 @@ import org.junit.Assert; ...@@ -22,7 +22,6 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
...@@ -30,11 +29,15 @@ import org.robolectric.Robolectric; ...@@ -30,11 +29,15 @@ import org.robolectric.Robolectric;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.omnibox.suggestions.base.BaseSuggestionViewProperties.Action;
import org.chromium.components.browser_ui.widget.RoundedCornerImageView; import org.chromium.components.browser_ui.widget.RoundedCornerImageView;
import org.chromium.testing.local.LocalRobolectricTestRunner; import org.chromium.testing.local.LocalRobolectricTestRunner;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor; import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import java.util.Arrays;
import java.util.List;
/** /**
* Tests for {@link BaseSuggestionViewBinder}. * Tests for {@link BaseSuggestionViewBinder}.
*/ */
...@@ -50,9 +53,6 @@ public class BaseSuggestionViewBinderUnitTest { ...@@ -50,9 +53,6 @@ public class BaseSuggestionViewBinderUnitTest {
@Mock @Mock
RoundedCornerImageView mIconView; RoundedCornerImageView mIconView;
@Mock
ImageView mActionView;
@Mock @Mock
ImageView mContentView; ImageView mContentView;
...@@ -65,17 +65,19 @@ public class BaseSuggestionViewBinderUnitTest { ...@@ -65,17 +65,19 @@ public class BaseSuggestionViewBinderUnitTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mActivity = Robolectric.buildActivity(Activity.class).setup().get(); mActivity = Robolectric.buildActivity(Activity.class).setup().get();
mActivity.setTheme(R.style.Light);
mResources = mActivity.getResources(); mResources = mActivity.getResources();
when(mBaseView.getContext()).thenReturn(mActivity); when(mContentView.getContext()).thenReturn(mActivity);
when(mIconView.getContext()).thenReturn(mActivity);
when(mActionView.getContext()).thenReturn(mActivity); mBaseView = spy(new BaseSuggestionView(mContentView));
when(mBaseView.getDecoratedSuggestionView()).thenReturn(mDecoratedView); when(mBaseView.getDecoratedSuggestionView()).thenReturn(mDecoratedView);
when(mBaseView.getSuggestionImageView()).thenReturn(mIconView); when(mBaseView.getSuggestionImageView()).thenReturn(mIconView);
when(mBaseView.getActionImageView()).thenReturn(mActionView);
when(mDecoratedView.getContentView()).thenReturn(mContentView);
when(mBaseView.getContentView()).thenReturn(mContentView); when(mBaseView.getContentView()).thenReturn(mContentView);
when(mDecoratedView.getContentView()).thenReturn(mContentView);
when(mDecoratedView.getResources()).thenReturn(mResources); when(mDecoratedView.getResources()).thenReturn(mResources);
when(mIconView.getContext()).thenReturn(mActivity);
mModel = new PropertyModel(BaseSuggestionViewProperties.ALL_KEYS); mModel = new PropertyModel(BaseSuggestionViewProperties.ALL_KEYS);
PropertyModelChangeProcessor.create(mModel, mBaseView, PropertyModelChangeProcessor.create(mModel, mBaseView,
...@@ -126,27 +128,93 @@ public class BaseSuggestionViewBinderUnitTest { ...@@ -126,27 +128,93 @@ public class BaseSuggestionViewBinderUnitTest {
} }
@Test @Test
public void actionIcon_showSquareIcon() { public void actionIcon_showIcon() {
SuggestionDrawableState state = SuggestionDrawableState.Builder.forColor(0).build(); Runnable callback = mock(Runnable.class);
mModel.set(BaseSuggestionViewProperties.ACTION_ICON, state); List<Action> list =
Arrays.asList(new Action(SuggestionDrawableState.Builder.forColor(0).build(),
verify(mActionView).setVisibility(View.VISIBLE); R.string.accessibility_omnibox_btn_refine, callback));
verify(mActionView).setImageDrawable(state.drawable); mModel.set(BaseSuggestionViewProperties.ACTIONS, list);
List<ImageView> actionButtons = mBaseView.getActionButtons();
Assert.assertEquals(1, actionButtons.size());
Assert.assertEquals(View.VISIBLE, actionButtons.get(0).getVisibility());
Assert.assertEquals(list.get(0).icon.drawable, actionButtons.get(0).getDrawable());
verify(mBaseView, times(1)).addView(actionButtons.get(0));
Assert.assertTrue(actionButtons.get(0).performClick());
Assert.assertTrue(actionButtons.get(0).performClick());
Assert.assertTrue(actionButtons.get(0).performClick());
verify(callback, times(3)).run();
} }
@Test @Test
public void actionIcon_hideIcon() { public void actionIcon_showMultipleIcons() {
InOrder ordered = inOrder(mActionView); Runnable call1 = mock(Runnable.class);
Runnable call2 = mock(Runnable.class);
SuggestionDrawableState state = SuggestionDrawableState.Builder.forColor(0).build(); Runnable call3 = mock(Runnable.class);
mModel.set(BaseSuggestionViewProperties.ACTION_ICON, state);
mModel.set(BaseSuggestionViewProperties.ACTION_ICON, null); List<Action> list =
Arrays.asList(new Action(SuggestionDrawableState.Builder.forColor(0).build(),
R.string.accessibility_omnibox_btn_refine, call1),
new Action(SuggestionDrawableState.Builder.forColor(0).build(),
R.string.accessibility_omnibox_btn_refine, call2),
new Action(SuggestionDrawableState.Builder.forColor(0).build(),
R.string.accessibility_omnibox_btn_refine, call3));
mModel.set(BaseSuggestionViewProperties.ACTIONS, list);
List<ImageView> actionButtons = mBaseView.getActionButtons();
Assert.assertEquals(3, actionButtons.size());
Assert.assertEquals(View.VISIBLE, actionButtons.get(0).getVisibility());
Assert.assertEquals(View.VISIBLE, actionButtons.get(1).getVisibility());
Assert.assertEquals(View.VISIBLE, actionButtons.get(2).getVisibility());
verify(mBaseView, times(1)).addView(actionButtons.get(0));
verify(mBaseView, times(1)).addView(actionButtons.get(1));
verify(mBaseView, times(1)).addView(actionButtons.get(2));
Assert.assertEquals(list.get(0).icon.drawable, actionButtons.get(0).getDrawable());
Assert.assertEquals(list.get(1).icon.drawable, actionButtons.get(1).getDrawable());
Assert.assertEquals(list.get(2).icon.drawable, actionButtons.get(2).getDrawable());
Assert.assertTrue(actionButtons.get(0).performClick());
verify(call1, times(1)).run();
Assert.assertTrue(actionButtons.get(1).performClick());
verify(call2, times(1)).run();
Assert.assertTrue(actionButtons.get(2).performClick());
verify(call3, times(1)).run();
}
ordered.verify(mActionView).setVisibility(View.VISIBLE); @Test
ordered.verify(mActionView).setImageDrawable(state.drawable); public void actionIcon_hideIcons() {
ordered.verify(mActionView).setVisibility(View.GONE); final List<Action> list =
// Ensure we're releasing drawable to free memory. Arrays.asList(new Action(SuggestionDrawableState.Builder.forColor(0).build(),
ordered.verify(mActionView).setImageDrawable(null); R.string.accessibility_omnibox_btn_refine, () -> {}),
new Action(SuggestionDrawableState.Builder.forColor(0).build(),
R.string.accessibility_omnibox_btn_refine, () -> {}),
new Action(SuggestionDrawableState.Builder.forColor(0).build(),
R.string.accessibility_omnibox_btn_refine, () -> {}));
final List<ImageView> actionButtons = mBaseView.getActionButtons();
mModel.set(BaseSuggestionViewProperties.ACTIONS, list);
Assert.assertEquals(3, actionButtons.size());
final View actionButton1 = actionButtons.get(0);
final View actionButton2 = actionButtons.get(1);
final View actionButton3 = actionButtons.get(2);
verify(mBaseView, times(1)).addView(actionButton1);
verify(mBaseView, times(1)).addView(actionButton2);
verify(mBaseView, times(1)).addView(actionButton3);
mModel.set(BaseSuggestionViewProperties.ACTIONS, list.subList(0, 2));
Assert.assertEquals(2, actionButtons.size());
verify(mBaseView, times(1)).removeView(actionButton3);
mModel.set(BaseSuggestionViewProperties.ACTIONS, list.subList(0, 1));
Assert.assertEquals(1, actionButtons.size());
verify(mBaseView, times(1)).removeView(actionButton2);
mModel.set(BaseSuggestionViewProperties.ACTIONS, null);
Assert.assertEquals(0, actionButtons.size());
verify(mBaseView, times(1)).removeView(actionButton1);
} }
@Test @Test
...@@ -208,38 +276,4 @@ public class BaseSuggestionViewBinderUnitTest { ...@@ -208,38 +276,4 @@ public class BaseSuggestionViewBinderUnitTest {
verify(mContentView).setPaddingRelative(0, expectedPadding, 0, expectedPadding); verify(mContentView).setPaddingRelative(0, expectedPadding, 0, expectedPadding);
verify(mContentView).setMinimumHeight(expectedHeight); verify(mContentView).setMinimumHeight(expectedHeight);
} }
@Test
public void actionCallback_installedWhenSet() {
ArgumentCaptor<View.OnClickListener> callback =
ArgumentCaptor.forClass(View.OnClickListener.class);
Runnable mockCallback = mock(Runnable.class);
mModel.set(BaseSuggestionViewProperties.ACTION_CALLBACK, mockCallback);
verify(mActionView, times(1)).setOnClickListener(callback.capture());
callback.getValue().onClick(null);
verify(mockCallback, times(1)).run();
}
@Test
public void actionCallback_subsequentUpdatesReplaceCallback() {
ArgumentCaptor<View.OnClickListener> callback =
ArgumentCaptor.forClass(View.OnClickListener.class);
Runnable mockCallback1 = mock(Runnable.class);
Runnable mockCallback2 = mock(Runnable.class);
mModel.set(BaseSuggestionViewProperties.ACTION_CALLBACK, mockCallback1);
mModel.set(BaseSuggestionViewProperties.ACTION_CALLBACK, mockCallback2);
verify(mActionView, times(2)).setOnClickListener(callback.capture());
callback.getValue().onClick(null);
verify(mockCallback1, never()).run();
verify(mockCallback2, times(1)).run();
}
@Test
public void actionCallback_clearedWhenUnset() {
mModel.set(BaseSuggestionViewProperties.ACTION_CALLBACK, () -> {});
verify(mActionView, times(1)).setOnClickListener(any(View.OnClickListener.class));
mModel.set(BaseSuggestionViewProperties.ACTION_CALLBACK, null);
verify(mActionView, times(1)).setOnClickListener(null);
}
} }
...@@ -37,7 +37,6 @@ public class BaseSuggestionViewTest { ...@@ -37,7 +37,6 @@ public class BaseSuggestionViewTest {
private BaseSuggestionViewForTest mView; private BaseSuggestionViewForTest mView;
private Activity mActivity; private Activity mActivity;
private View mRefineView;
private View mDecoratedView; private View mDecoratedView;
private View mContentView; private View mContentView;
...@@ -78,14 +77,6 @@ public class BaseSuggestionViewTest { ...@@ -78,14 +77,6 @@ public class BaseSuggestionViewTest {
final int height = getMeasuredHeight(); final int height = getMeasuredHeight();
onLayout(true, 0, 0, width, height); onLayout(true, 0, 0, width, height);
} }
View getDecoratedView() {
return mDecoratedView;
}
View getRefineView() {
return mActionView;
}
} }
@Before @Before
...@@ -100,8 +91,7 @@ public class BaseSuggestionViewTest { ...@@ -100,8 +91,7 @@ public class BaseSuggestionViewTest {
mActionIconWidthPx = mActivity.getResources().getDimensionPixelSize( mActionIconWidthPx = mActivity.getResources().getDimensionPixelSize(
R.dimen.omnibox_suggestion_action_icon_width); R.dimen.omnibox_suggestion_action_icon_width);
mRefineView = mView.getRefineView(); mDecoratedView = mView.getDecoratedSuggestionView();
mDecoratedView = mView.getDecoratedView();
} }
/** /**
...@@ -134,6 +124,82 @@ public class BaseSuggestionViewTest { ...@@ -134,6 +124,82 @@ public class BaseSuggestionViewTest {
Assert.assertThat("view height", v.getMeasuredHeight(), lessThanOrEqualTo(bottom - top)); Assert.assertThat("view height", v.getMeasuredHeight(), lessThanOrEqualTo(bottom - top));
} }
@Test
public void layout_LtrMultipleActionButtonsVisible() {
final int useContentWidth = 320;
final int paddingStart = 12;
final int paddingEnd = 34;
final int giveSuggestionWidth =
useContentWidth + 3 * mActionIconWidthPx + paddingStart + paddingEnd;
final int giveContentHeight = 15;
final int expectedContentLeft = paddingStart;
final int expectedContentRight = expectedContentLeft + useContentWidth;
final int expectedRefine1Left = expectedContentRight;
final int expectedRefine1Right = expectedRefine1Left + mActionIconWidthPx;
final int expectedRefine2Left = expectedRefine1Right;
final int expectedRefine2Right = expectedRefine2Left + mActionIconWidthPx;
final int expectedRefine3Left = expectedRefine2Right;
final int expectedRefine3Right = giveSuggestionWidth - paddingEnd;
mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0);
mView.setActionButtonsCount(3);
final View actionButton1 = (View) mView.getActionButtons().get(0);
final View actionButton2 = (View) mView.getActionButtons().get(1);
final View actionButton3 = (View) mView.getActionButtons().get(2);
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_LTR);
verifyViewLayout(
actionButton1, expectedRefine1Left, 0, expectedRefine1Right, giveContentHeight);
verifyViewLayout(
actionButton2, expectedRefine2Left, 0, expectedRefine2Right, giveContentHeight);
verifyViewLayout(
actionButton3, expectedRefine3Left, 0, expectedRefine3Right, giveContentHeight);
verifyViewLayout(
mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
}
@Test
public void layout_RtlMultipleActionButtonsVisible() {
final int useContentWidth = 220;
final int paddingStart = 13;
final int paddingEnd = 57;
final int giveSuggestionWidth =
useContentWidth + 3 * mActionIconWidthPx + paddingStart + paddingEnd;
final int giveContentHeight = 25;
final int expectedRefine1Left = paddingEnd;
final int expectedRefine1Right = expectedRefine1Left + mActionIconWidthPx;
final int expectedRefine2Left = expectedRefine1Right;
final int expectedRefine2Right = expectedRefine2Left + mActionIconWidthPx;
final int expectedRefine3Left = expectedRefine2Right;
final int expectedRefine3Right = expectedRefine3Left + mActionIconWidthPx;
final int expectedContentLeft = expectedRefine3Right;
final int expectedContentRight = giveSuggestionWidth - paddingStart;
mView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0);
mView.setActionButtonsCount(3);
// Note: reverse order, because we also want to show these buttons in reverse order.
final View actionButton1 = (View) mView.getActionButtons().get(2);
final View actionButton2 = (View) mView.getActionButtons().get(1);
final View actionButton3 = (View) mView.getActionButtons().get(0);
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_RTL);
verifyViewLayout(
actionButton1, expectedRefine1Left, 0, expectedRefine1Right, giveContentHeight);
verifyViewLayout(
actionButton2, expectedRefine2Left, 0, expectedRefine2Right, giveContentHeight);
verifyViewLayout(
actionButton3, expectedRefine3Left, 0, expectedRefine3Right, giveContentHeight);
verifyViewLayout(
mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
}
@Test @Test
public void layout_LtrRefineVisible() { public void layout_LtrRefineVisible() {
final int useContentWidth = 120; final int useContentWidth = 120;
...@@ -160,10 +226,13 @@ public class BaseSuggestionViewTest { ...@@ -160,10 +226,13 @@ public class BaseSuggestionViewTest {
final int expectedRefineRight = giveSuggestionWidth - paddingEnd; final int expectedRefineRight = giveSuggestionWidth - paddingEnd;
mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0); mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0);
mView.setActionButtonsCount(1);
final View actionButton = (View) mView.getActionButtons().get(0);
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_LTR); executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_LTR);
verifyViewLayout( verifyViewLayout(
mRefineView, expectedRefineLeft, 0, expectedRefineRight, giveContentHeight); actionButton, expectedRefineLeft, 0, expectedRefineRight, giveContentHeight);
verifyViewLayout( verifyViewLayout(
mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight); mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
} }
...@@ -195,10 +264,13 @@ public class BaseSuggestionViewTest { ...@@ -195,10 +264,13 @@ public class BaseSuggestionViewTest {
mView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); mView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0); mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0);
mView.setActionButtonsCount(1);
final View actionButton = (View) mView.getActionButtons().get(0);
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_RTL); executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_RTL);
verifyViewLayout( verifyViewLayout(
mRefineView, expectedRefineLeft, 0, expectedRefineRight, giveContentHeight); actionButton, expectedRefineLeft, 0, expectedRefineRight, giveContentHeight);
verifyViewLayout( verifyViewLayout(
mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight); mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
} }
...@@ -224,8 +296,6 @@ public class BaseSuggestionViewTest { ...@@ -224,8 +296,6 @@ public class BaseSuggestionViewTest {
final int expectedContentLeft = paddingStart; final int expectedContentLeft = paddingStart;
final int expectedContentRight = giveSuggestionWidth - paddingEnd; final int expectedContentRight = giveSuggestionWidth - paddingEnd;
mRefineView.setVisibility(View.GONE);
mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0); mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0);
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_LTR); executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_LTR);
verifyViewLayout( verifyViewLayout(
...@@ -253,8 +323,6 @@ public class BaseSuggestionViewTest { ...@@ -253,8 +323,6 @@ public class BaseSuggestionViewTest {
final int expectedContentLeft = paddingEnd; final int expectedContentLeft = paddingEnd;
final int expectedContentRight = giveSuggestionWidth - paddingStart; final int expectedContentRight = giveSuggestionWidth - paddingStart;
mRefineView.setVisibility(View.GONE);
mView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); mView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0); mView.setPaddingRelative(paddingStart, 0, paddingEnd, 0);
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_RTL); executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_RTL);
......
...@@ -253,11 +253,11 @@ public class BasicSuggestionProcessorUnitTest { ...@@ -253,11 +253,11 @@ public class BasicSuggestionProcessorUnitTest {
createSearchSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, typed, ""); createSearchSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, typed, "");
PropertyModel model = mProcessor.createModel(); PropertyModel model = mProcessor.createModel();
mProcessor.populateModel(mSuggestion, model, 0); mProcessor.populateModel(mSuggestion, model, 0);
Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTION_CALLBACK)); Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTIONS));
createUrlSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, typed, ""); createUrlSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, typed, "");
mProcessor.populateModel(mSuggestion, model, 0); mProcessor.populateModel(mSuggestion, model, 0);
Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTION_CALLBACK)); Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTIONS));
} }
@CalledByNativeJavaTest @CalledByNativeJavaTest
...@@ -268,11 +268,11 @@ public class BasicSuggestionProcessorUnitTest { ...@@ -268,11 +268,11 @@ public class BasicSuggestionProcessorUnitTest {
createSearchSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, refined, ""); createSearchSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, refined, "");
PropertyModel model = mProcessor.createModel(); PropertyModel model = mProcessor.createModel();
mProcessor.populateModel(mSuggestion, model, 0); mProcessor.populateModel(mSuggestion, model, 0);
Assert.assertNotNull(mModel.get(BaseSuggestionViewProperties.ACTION_CALLBACK)); Assert.assertNotNull(mModel.get(BaseSuggestionViewProperties.ACTIONS));
createUrlSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, refined, ""); createUrlSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, refined, "");
mProcessor.populateModel(mSuggestion, model, 0); mProcessor.populateModel(mSuggestion, model, 0);
Assert.assertNotNull(mModel.get(BaseSuggestionViewProperties.ACTION_CALLBACK)); Assert.assertNotNull(mModel.get(BaseSuggestionViewProperties.ACTIONS));
} }
@CalledByNativeJavaTest @CalledByNativeJavaTest
......
...@@ -122,13 +122,13 @@ public class ClipboardSuggestionProcessorTest { ...@@ -122,13 +122,13 @@ public class ClipboardSuggestionProcessorTest {
@CalledByNativeJavaTest @CalledByNativeJavaTest
public void clipboardSuggestion_doesNotRefine() { public void clipboardSuggestion_doesNotRefine() {
createClipboardSuggestion(OmniboxSuggestionType.CLIPBOARD_URL, GURL.emptyGURL()); createClipboardSuggestion(OmniboxSuggestionType.CLIPBOARD_URL, GURL.emptyGURL());
Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTION_CALLBACK)); Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTIONS));
createClipboardSuggestion(OmniboxSuggestionType.CLIPBOARD_TEXT, GURL.emptyGURL()); createClipboardSuggestion(OmniboxSuggestionType.CLIPBOARD_TEXT, GURL.emptyGURL());
Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTION_CALLBACK)); Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTIONS));
createClipboardSuggestion(OmniboxSuggestionType.CLIPBOARD_IMAGE, GURL.emptyGURL()); createClipboardSuggestion(OmniboxSuggestionType.CLIPBOARD_IMAGE, GURL.emptyGURL());
Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTION_CALLBACK)); Assert.assertNull(mModel.get(BaseSuggestionViewProperties.ACTIONS));
} }
@CalledByNativeJavaTest @CalledByNativeJavaTest
......
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