Commit 3e300603 authored by Friedrich Horschig's avatar Friedrich Horschig Committed by Commit Bot

[Android] Make accessory data providers use objects instead of arrays

This small refactoring enables the provides to be used for objects
instead of arrays which will come in handy for the AccessoryData type
that is introduced with https://crrev.com/c/1320732

TBR=rouslan@chromium.org

Change-Id: I237813484c1ffcfe0357a30672b893db9c9b2d32
Reviewed-on: https://chromium-review.googlesource.com/c/1326512Reviewed-by: default avatarFriedrich Horschig [CET] <fhorschig@chromium.org>
Reviewed-by: default avatarIoana Pandele <ioanap@chromium.org>
Commit-Queue: Friedrich Horschig [CET] <fhorschig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607191}
parent 251b2c57
......@@ -37,7 +37,7 @@ public class AutofillKeyboardAccessoryBridge
private long mNativeAutofillKeyboardAccessory;
private ManualFillingCoordinator mManualFillingCoordinator;
private Context mContext;
private KeyboardAccessoryData.Provider<KeyboardAccessoryData.Action> mChipProvider =
private KeyboardAccessoryData.Provider<KeyboardAccessoryData.Action[]> mChipProvider =
new KeyboardAccessoryData.PropertyProvider<>(AccessoryAction.AUTOFILL_SUGGESTION);
private AutofillKeyboardAccessoryBridge() {
......@@ -97,7 +97,7 @@ public class AutofillKeyboardAccessoryBridge
if (mContext instanceof ChromeActivity) {
mManualFillingCoordinator = ((ChromeActivity) mContext).getManualFillingController();
if (mManualFillingCoordinator.getKeyboardAccessory() != null) {
mManualFillingCoordinator.getKeyboardAccessory().registerActionListProvider(
mManualFillingCoordinator.getKeyboardAccessory().registerActionProvider(
mChipProvider);
}
}
......
......@@ -147,8 +147,8 @@ public class KeyboardAccessoryCoordinator {
*
* @param provider The object providing action lists to observers in this component.
*/
public void registerActionListProvider(
KeyboardAccessoryData.Provider<KeyboardAccessoryData.Action> provider) {
public void registerActionProvider(
KeyboardAccessoryData.Provider<KeyboardAccessoryData.Action[]> provider) {
provider.addObserver(mMediator);
}
......
......@@ -21,40 +21,37 @@ import java.util.List;
*/
public class KeyboardAccessoryData {
/**
* A provider notifies all registered {@link Observer} if the list of actions
* changes.
* TODO(fhorschig): Replace with android.databinding.ObservableField if available.
* @param <T> Either an {@link Action} or a {@link Tab} that this instance provides.
* A provider notifies all registered {@link Observer}s about a changed object.
* @param <T> The object this provider provides.
*/
public interface Provider<T> {
/**
* Every observer added by this need to be notified whenever the list of items changes.
* Every observer added by this needs to be notified whenever the object changes.
* @param observer The observer to be notified.
*/
void addObserver(Observer<T> observer);
/**
* Passes the given items to all subscribed {@link Observer}s.
* @param items The array of items to be passed to the {@link Observer}s.
* Passes the given item to all subscribed {@link Observer}s.
* @param item The item to be passed to the {@link Observer}s.
*/
void notifyObservers(T[] items);
void notifyObservers(T item);
}
/**
* An observer receives notifications from an {@link Provider} it is subscribed to.
* @param <T> An {@link Action}, {@link Tab} or {@link Item} that this instance observes.
* @param <T> Any object that this instance observes.
*/
public interface Observer<T> {
int DEFAULT_TYPE = Integer.MIN_VALUE;
/**
* A provider calls this function with a list of items that should be available in the
* keyboard accessory.
* A provider calls this function with an item that should be available in the keyboard
* accessory.
* @param typeId Specifies which type of item this update affects.
* @param items The items to be displayed in the Accessory. It's a native array as the
* provider is typically a bridge called via JNI which prefers native types.
* @param item An item to be displayed in the Accessory.
*/
void onItemsAvailable(int typeId, T[] items);
void onItemAvailable(int typeId, T item);
}
/**
......@@ -485,8 +482,8 @@ public class KeyboardAccessoryData {
/**
* A simple class that holds a list of {@link Observer}s which can be notified about new data by
* directly passing that data into {@link PropertyProvider#notifyObservers(T[])}.
* @param <T> Either {@link Action}s or {@link Tab}s provided by this class.
* directly passing that data into {@link PropertyProvider#notifyObservers(T)}.
* @param <T> The object this provider provides.
*/
public static class PropertyProvider<T> implements Provider<T> {
private final List<Observer<T>> mObservers = new ArrayList<>();
......@@ -506,9 +503,9 @@ public class KeyboardAccessoryData {
}
@Override
public void notifyObservers(T[] items) {
public void notifyObservers(T item) {
for (Observer<T> observer : mObservers) {
observer.onItemsAvailable(mType, items);
observer.onItemAvailable(mType, item);
}
}
}
......
......@@ -38,7 +38,7 @@ import java.util.List;
class KeyboardAccessoryMediator
implements ListObservable.ListObserver<Void>,
PropertyObservable.PropertyObserver<PropertyKey>,
KeyboardAccessoryData.Observer<KeyboardAccessoryData.Action>,
KeyboardAccessoryData.Observer<KeyboardAccessoryData.Action[]>,
TabLayout.OnTabSelectedListener {
private final PropertyModel mModel;
private final VisibilityDelegate mVisibilityDelegate;
......@@ -57,7 +57,7 @@ class KeyboardAccessoryMediator
}
@Override
public void onItemsAvailable(int typeId, KeyboardAccessoryData.Action[] actions) {
public void onItemAvailable(int typeId, KeyboardAccessoryData.Action[] actions) {
assert typeId != DEFAULT_TYPE : "Did not specify which Action type has been updated.";
// If there is a new list, retain all actions that are of a different type than the provided
// actions.
......@@ -138,7 +138,7 @@ class KeyboardAccessoryMediator
mVisibilityDelegate.onBottomControlSpaceChanged();
if (!mModel.get(VISIBLE)) {
// TODO(fhorschig|ioanap): Maybe the generation bridge should take care of that.
onItemsAvailable(AccessoryAction.GENERATE_PASSWORD_AUTOMATIC, new Action[0]);
onItemAvailable(AccessoryAction.GENERATE_PASSWORD_AUTOMATIC, new Action[0]);
}
return;
}
......
......@@ -91,11 +91,11 @@ public class ManualFillingCoordinator {
}
void registerActionProvider(
KeyboardAccessoryData.PropertyProvider<KeyboardAccessoryData.Action> actionProvider) {
KeyboardAccessoryData.PropertyProvider<KeyboardAccessoryData.Action[]> actionProvider) {
mMediator.registerActionProvider(actionProvider);
}
void registerPasswordProvider(Provider<KeyboardAccessoryData.Item> itemProvider) {
void registerPasswordProvider(Provider<KeyboardAccessoryData.Item[]> itemProvider) {
mMediator.registerPasswordProvider(itemProvider);
}
......
......@@ -54,8 +54,9 @@ class ManualFillingMediator extends EmptyTabObserver
* Provides a cache for a given Provider which can repeat the last notification to all
* observers.
*/
private class ActionProviderCacheAdapter extends KeyboardAccessoryData.PropertyProvider<Action>
implements KeyboardAccessoryData.Observer<Action> {
private class ActionProviderCacheAdapter
extends KeyboardAccessoryData.PropertyProvider<Action[]>
implements KeyboardAccessoryData.Observer<Action[]> {
private final Tab mTab;
private Action[] mLastItems;
......@@ -66,8 +67,8 @@ class ManualFillingMediator extends EmptyTabObserver
* @param provider The {@link Provider} to observe and whose data to cache.
* @param defaultItems The items to be notified about if the Provider hasn't provided any.
*/
ActionProviderCacheAdapter(Tab tab, KeyboardAccessoryData.PropertyProvider<Action> provider,
Action[] defaultItems) {
ActionProviderCacheAdapter(Tab tab,
KeyboardAccessoryData.PropertyProvider<Action[]> provider, Action[] defaultItems) {
super(provider.mType);
mTab = tab;
provider.addObserver(this);
......@@ -75,7 +76,7 @@ class ManualFillingMediator extends EmptyTabObserver
}
/**
* Calls {@link #onItemsAvailable} with the last used items again. If there haven't been
* Calls {@link #onItemAvailable} with the last used items again. If there haven't been
* any calls, call it with an empty list to avoid putting observers in an undefined state.
*/
void notifyAboutCachedItems() {
......@@ -83,7 +84,7 @@ class ManualFillingMediator extends EmptyTabObserver
}
@Override
public void onItemsAvailable(int typeId, Action[] actions) {
public void onItemAvailable(int typeId, Action[] actions) {
mLastItems = actions;
// Update the contents immediately, if the adapter connects to an active element.
if (mTab == mActiveBrowserTab) notifyObservers(actions);
......@@ -211,19 +212,19 @@ class ManualFillingMediator extends EmptyTabObserver
}
}
void registerPasswordProvider(Provider<KeyboardAccessoryData.Item> itemProvider) {
void registerPasswordProvider(Provider<KeyboardAccessoryData.Item[]> itemProvider) {
PasswordAccessorySheetCoordinator accessorySheet = getPasswordAccessorySheet();
if (accessorySheet == null) return; // Not available or initialized yet.
accessorySheet.registerItemProvider(itemProvider);
}
void registerActionProvider(KeyboardAccessoryData.PropertyProvider<Action> actionProvider) {
void registerActionProvider(KeyboardAccessoryData.PropertyProvider<Action[]> actionProvider) {
if (!isInitialized()) return;
if (mActiveBrowserTab == null) return;
ActionProviderCacheAdapter adapter =
new ActionProviderCacheAdapter(mActiveBrowserTab, actionProvider, new Action[0]);
mModel.get(mActiveBrowserTab).mActionsProvider = adapter;
mKeyboardAccessory.registerActionListProvider(adapter);
mKeyboardAccessory.registerActionProvider(adapter);
}
void destroy() {
......
......@@ -22,9 +22,9 @@ import java.util.ArrayList;
import java.util.List;
class PasswordAccessoryBridge {
private final KeyboardAccessoryData.PropertyProvider<Item> mItemProvider =
private final KeyboardAccessoryData.PropertyProvider<Item[]> mItemProvider =
new KeyboardAccessoryData.PropertyProvider<>();
private final KeyboardAccessoryData.PropertyProvider<Action> mActionProvider =
private final KeyboardAccessoryData.PropertyProvider<Action[]> mActionProvider =
new KeyboardAccessoryData.PropertyProvider<>(
AccessoryAction.GENERATE_PASSWORD_AUTOMATIC);
private final ManualFillingCoordinator mManualFillingCoordinator;
......
......@@ -27,7 +27,8 @@ import org.chromium.chrome.browser.modelutil.SimpleRecyclerViewMcp;
public class PasswordAccessorySheetCoordinator implements KeyboardAccessoryData.Tab.Listener {
private final Context mContext;
private final ListModel<Item> mModel = new ListModel<>();
private final KeyboardAccessoryData.Observer<Item> mMediator = (t, items) -> mModel.set(items);
private final KeyboardAccessoryData.Observer<Item[]> mMediator =
(t, items) -> mModel.set(items);
private final KeyboardAccessoryData.Tab mTab;
......@@ -101,10 +102,10 @@ public class PasswordAccessorySheetCoordinator implements KeyboardAccessoryData.
// TODO(fhorschig): There is only one. Make this a ctor param and self-destruct with it.
/**
* Registered item providers can replace the currently shown data in the password sheet.
* @param actionProvider The provider this component will listen to.
* @param itemProvider The provider this component will listen to.
*/
public void registerItemProvider(KeyboardAccessoryData.Provider<Item> actionProvider) {
actionProvider.addObserver(mMediator);
public void registerItemProvider(KeyboardAccessoryData.Provider<Item[]> itemProvider) {
itemProvider.addObserver(mMediator);
}
/**
......
......@@ -176,7 +176,7 @@ public class ManualFillingTestHelper {
* Creates and adds a password tab to keyboard accessory and sheet.
*/
public void createTestTab() {
KeyboardAccessoryData.Provider<KeyboardAccessoryData.Item> provider =
KeyboardAccessoryData.Provider<KeyboardAccessoryData.Item[]> provider =
new KeyboardAccessoryData.PropertyProvider<>();
mActivityTestRule.getActivity().getManualFillingController().registerPasswordProvider(
provider);
......
......@@ -254,7 +254,7 @@ public class PasswordAccessoryIntegrationTest {
* @param items The items to be provided to the password accessory sheet.
*/
private void provideItems(Item[] items) {
KeyboardAccessoryData.PropertyProvider<Item> itemProvider =
KeyboardAccessoryData.PropertyProvider<Item[]> itemProvider =
new KeyboardAccessoryData.PropertyProvider<>();
mActivityTestRule.getActivity()
.getManualFillingController()
......
......@@ -119,8 +119,9 @@ public class KeyboardAccessoryControllerTest {
public void testModelNotifiesAboutActionsChangedByProvider() {
mModel.get(ACTIONS).addObserver(mMockActionListObserver);
PropertyProvider<Action> testProvider = new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
mCoordinator.registerActionListProvider(testProvider);
PropertyProvider<Action[]> testProvider =
new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
mCoordinator.registerActionProvider(testProvider);
// If the coordinator receives an initial actions, the model should report an insertion.
mCoordinator.requestShowing();
......@@ -182,10 +183,10 @@ public class KeyboardAccessoryControllerTest {
@Test
public void testIsVisibleWithSuggestionsBeforeKeyboardComesUp() {
KeyboardAccessoryData.PropertyProvider<Action> autofillSuggestionProvider =
KeyboardAccessoryData.PropertyProvider<Action[]> autofillSuggestionProvider =
new KeyboardAccessoryData.PropertyProvider<>(AUTOFILL_SUGGESTION);
Action suggestion = new Action("Suggestion", AUTOFILL_SUGGESTION, (a) -> {});
mCoordinator.registerActionListProvider(autofillSuggestionProvider);
mCoordinator.registerActionProvider(autofillSuggestionProvider);
// Without suggestions, the accessory should remain invisible - even if the keyboard shows.
assertThat(mModel.get(ACTIONS).size(), is(0));
......@@ -206,10 +207,10 @@ public class KeyboardAccessoryControllerTest {
@Test
public void testIsVisibleWithSuggestionsAfterKeyboardComesUp() {
KeyboardAccessoryData.PropertyProvider<Action> autofillSuggestionProvider =
KeyboardAccessoryData.PropertyProvider<Action[]> autofillSuggestionProvider =
new KeyboardAccessoryData.PropertyProvider<>(AUTOFILL_SUGGESTION);
Action suggestion = new Action("Suggestion", AUTOFILL_SUGGESTION, (a) -> {});
mCoordinator.registerActionListProvider(autofillSuggestionProvider);
mCoordinator.registerActionProvider(autofillSuggestionProvider);
// Without any suggestions, the accessory should remain invisible.
assertThat(mModel.get(VISIBLE), is(false));
......@@ -239,13 +240,13 @@ public class KeyboardAccessoryControllerTest {
@Test
public void testSortsActionsBasedOnType() {
KeyboardAccessoryData.PropertyProvider<Action> generationProvider =
KeyboardAccessoryData.PropertyProvider<Action[]> generationProvider =
new KeyboardAccessoryData.PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
KeyboardAccessoryData.PropertyProvider<Action> autofillSuggestionProvider =
KeyboardAccessoryData.PropertyProvider<Action[]> autofillSuggestionProvider =
new KeyboardAccessoryData.PropertyProvider<>(AUTOFILL_SUGGESTION);
mCoordinator.registerActionListProvider(generationProvider);
mCoordinator.registerActionListProvider(autofillSuggestionProvider);
mCoordinator.registerActionProvider(generationProvider);
mCoordinator.registerActionProvider(autofillSuggestionProvider);
Action suggestion1 = new Action("FirstSuggestion", AUTOFILL_SUGGESTION, (a) -> {});
Action suggestion2 = new Action("SecondSuggestion", AUTOFILL_SUGGESTION, (a) -> {});
......@@ -262,13 +263,13 @@ public class KeyboardAccessoryControllerTest {
@Test
public void testDeletingActionsAffectsOnlyOneType() {
KeyboardAccessoryData.PropertyProvider<Action> generationProvider =
KeyboardAccessoryData.PropertyProvider<Action[]> generationProvider =
new KeyboardAccessoryData.PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
KeyboardAccessoryData.PropertyProvider<Action> autofillSuggestionProvider =
KeyboardAccessoryData.PropertyProvider<Action[]> autofillSuggestionProvider =
new KeyboardAccessoryData.PropertyProvider<>(AUTOFILL_SUGGESTION);
mCoordinator.registerActionListProvider(generationProvider);
mCoordinator.registerActionListProvider(autofillSuggestionProvider);
mCoordinator.registerActionProvider(generationProvider);
mCoordinator.registerActionProvider(autofillSuggestionProvider);
Action suggestion = new Action("NewSuggestion", AUTOFILL_SUGGESTION, (a) -> {});
Action generationAction = new Action("Generate", GENERATE_PASSWORD_AUTOMATIC, (a) -> {});
......@@ -357,10 +358,10 @@ public class KeyboardAccessoryControllerTest {
// Adding suggestions adds to the suggestions bucket - and again to tabs and total.
mCoordinator.close(); // Hide, so it's brought up again.
KeyboardAccessoryData.PropertyProvider<Action> autofillSuggestionProvider =
KeyboardAccessoryData.PropertyProvider<Action[]> autofillSuggestionProvider =
new KeyboardAccessoryData.PropertyProvider<>(AUTOFILL_SUGGESTION);
Action suggestion = new Action("Suggestion", AUTOFILL_SUGGESTION, (a) -> {});
mCoordinator.registerActionListProvider(autofillSuggestionProvider);
mCoordinator.registerActionProvider(autofillSuggestionProvider);
autofillSuggestionProvider.notifyObservers(new Action[] {suggestion});
mCoordinator.requestShowing();
......@@ -399,10 +400,10 @@ public class KeyboardAccessoryControllerTest {
assertThat(getShownMetricsCount(AccessoryBarContents.WITH_ACTIONS), is(1));
assertThat(getShownMetricsCount(AccessoryBarContents.ANY_CONTENTS), is(1));
KeyboardAccessoryData.PropertyProvider<Action> autofillSuggestionProvider =
KeyboardAccessoryData.PropertyProvider<Action[]> autofillSuggestionProvider =
new KeyboardAccessoryData.PropertyProvider<>(AUTOFILL_SUGGESTION);
Action suggestion = new Action("Suggestion", AUTOFILL_SUGGESTION, (a) -> {});
mCoordinator.registerActionListProvider(autofillSuggestionProvider);
mCoordinator.registerActionProvider(autofillSuggestionProvider);
autofillSuggestionProvider.notifyObservers(new Action[] {suggestion});
assertThat(getShownMetricsCount(AccessoryBarContents.WITH_AUTOFILL_SUGGESTIONS), is(1));
......
......@@ -171,8 +171,8 @@ public class ManualFillingControllerTest {
@Test
public void testPasswordItemsPersistAfterSwitchingBrowserTabs() {
ManualFillingMediator mediator = mController.getMediatorForTesting();
Provider<Item> firstTabProvider = new PropertyProvider<>();
Provider<Item> secondTabProvider = new PropertyProvider<>();
Provider<Item[]> firstTabProvider = new PropertyProvider<>();
Provider<Item[]> secondTabProvider = new PropertyProvider<>();
// Simulate opening a new tab which automatically triggers the registration:
Tab firstTab = addTab(mediator, 1111, null);
......@@ -204,9 +204,9 @@ public class ManualFillingControllerTest {
@Test
public void testKeyboardAccessoryActionsPersistAfterSwitchingBrowserTabs() {
ManualFillingMediator mediator = mController.getMediatorForTesting();
PropertyProvider<Action> firstTabProvider =
PropertyProvider<Action[]> firstTabProvider =
new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
PropertyProvider<Action> secondTabProvider =
PropertyProvider<Action[]> secondTabProvider =
new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
ListModel<Action> keyboardActions =
mediator.getKeyboardAccessory().getMediatorForTesting().getModelForTesting().get(
......@@ -328,14 +328,12 @@ public class ManualFillingControllerTest {
// Open a tab.
Tab tab = addTab(mediator, 1111, null);
// Add an action provider that never provided actions.
mController.registerActionProvider(
new PropertyProvider<Action>(GENERATE_PASSWORD_AUTOMATIC));
mController.registerActionProvider(new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC));
assertThat(keyboardAccessoryModel.get(KeyboardAccessoryProperties.ACTIONS).size(), is(0));
// Create a new tab with an action:
Tab secondTab = addTab(mediator, 1111, tab);
PropertyProvider<Action> provider =
new PropertyProvider<Action>(GENERATE_PASSWORD_AUTOMATIC);
PropertyProvider<Action[]> provider = new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
mController.registerActionProvider(provider);
provider.notifyObservers(new Action[] {
new Action("Test Action", GENERATE_PASSWORD_AUTOMATIC, (action) -> {})});
......@@ -354,15 +352,14 @@ public class ManualFillingControllerTest {
// Open a tab.
Tab tab = addTab(mediator, 1111, null);
// Add an action provider that hasn't provided actions yet.
PropertyProvider<Action> delayedProvider =
PropertyProvider<Action[]> delayedProvider =
new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
mController.registerActionProvider(delayedProvider);
assertThat(keyboardAccessoryModel.get(KeyboardAccessoryProperties.ACTIONS).size(), is(0));
// Create and switch to a new tab:
Tab secondTab = addTab(mediator, 1111, tab);
PropertyProvider<Action> provider =
new PropertyProvider<Action>(GENERATE_PASSWORD_AUTOMATIC);
PropertyProvider<Action[]> provider = new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
mController.registerActionProvider(provider);
// And provide data to the active tab.
......@@ -396,12 +393,12 @@ public class ManualFillingControllerTest {
.getMediatorForTesting()
.getModelForTesting();
Provider<Item> firstTabProvider = new PropertyProvider<>();
PropertyProvider<Action> firstActionProvider =
new PropertyProvider<Action>(GENERATE_PASSWORD_AUTOMATIC);
Provider<Item> secondTabProvider = new PropertyProvider<>();
PropertyProvider<Action> secondActionProvider =
new PropertyProvider<Action>(GENERATE_PASSWORD_AUTOMATIC);
Provider<Item[]> firstTabProvider = new PropertyProvider<>();
PropertyProvider<Action[]> firstActionProvider =
new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
Provider<Item[]> secondTabProvider = new PropertyProvider<>();
PropertyProvider<Action[]> secondActionProvider =
new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
// Simulate opening a new tab:
Tab firstTab = addTab(mediator, 1111, null);
......
......@@ -73,7 +73,7 @@ public class PasswordAccessorySheetControllerTest {
@Test
public void testModelNotifiesAboutActionsChangedByProvider() {
final KeyboardAccessoryData.PropertyProvider<Item> testProvider =
final KeyboardAccessoryData.PropertyProvider<Item[]> testProvider =
new KeyboardAccessoryData.PropertyProvider<>();
final Item testItem = Item.createLabel("Test Item", null);
......
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