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

[Mfill Android] Use AccessorySheetData in UI

This CL moves the transformation of AccessorySheetTab data to
KeyboardAccessoryData.Items from the ManualFillingBridge into the
PasswordsAccessorySheetMediator.
This enables replacing the Items in a follow-up CL completely and use
the AccessorySheetTab to implement the new layout for the passwords.

This is a step towards generalization of accessory sheet tabs as new
tab will be able to add separate element types with respective views.

Bug: 853772
Change-Id: I678d453245568ef006de932274db044b14ffbdfa
Reviewed-on: https://chromium-review.googlesource.com/c/1350890Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarIoana Pandele <ioanap@chromium.org>
Commit-Queue: Friedrich Horschig [CET] <fhorschig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#613040}
parent 0b9341b1
......@@ -339,6 +339,7 @@ public class KeyboardAccessoryData {
*/
public final static class UserInfo {
private final List<Field> mFields = new ArrayList<>();
private final @Nullable Item.FaviconProvider mFaviconProvider;
/**
* Represents an item (either selectable or not) presented on the UI, such as the username
......@@ -403,7 +404,9 @@ public class KeyboardAccessoryData {
}
}
public UserInfo() {}
public UserInfo(@Nullable Item.FaviconProvider faviconProvider) {
mFaviconProvider = faviconProvider;
}
/**
* Adds a new field to the group.
......@@ -419,6 +422,14 @@ public class KeyboardAccessoryData {
public List<Field> getFields() {
return mFields;
}
/**
* Possibly holds a favicon provider.
* @return A {@link Item.FaviconProvider}. Optional.
*/
public @Nullable Item.FaviconProvider getFaviconProvider() {
return mFaviconProvider;
}
}
/**
......
......@@ -14,15 +14,11 @@ import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Action;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.FooterCommand;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo;
import org.chromium.ui.base.WindowAndroid;
import java.util.ArrayList;
import java.util.List;
class ManualFillingBridge {
private final KeyboardAccessoryData.PropertyProvider<Item[]> mItemProvider =
private final KeyboardAccessoryData.PropertyProvider<AccessorySheetData> mSheetDataProvider =
new KeyboardAccessoryData.PropertyProvider<>();
private final KeyboardAccessoryData.PropertyProvider<Action[]> mActionProvider =
new KeyboardAccessoryData.PropertyProvider<>(
......@@ -35,7 +31,7 @@ class ManualFillingBridge {
mNativeView = nativeView;
mActivity = (ChromeActivity) windowAndroid.getActivity().get();
mManualFillingCoordinator = mActivity.getManualFillingController();
mManualFillingCoordinator.registerPasswordProvider(mItemProvider);
mManualFillingCoordinator.registerPasswordProvider(mSheetDataProvider);
mManualFillingCoordinator.registerActionProvider(mActionProvider);
}
......@@ -46,7 +42,7 @@ class ManualFillingBridge {
@CalledByNative
private void onItemsAvailable(Object objAccessorySheetData) {
mItemProvider.notifyObservers(convertToItems((AccessorySheetData) objAccessorySheetData));
mSheetDataProvider.notifyObservers((AccessorySheetData) objAccessorySheetData);
}
@CalledByNative
......@@ -97,7 +93,7 @@ class ManualFillingBridge {
@CalledByNative
private void destroy() {
mItemProvider.notifyObservers(new Item[] {}); // There are no more items available!
mSheetDataProvider.notifyObservers(null);
mNativeView = 0;
}
......@@ -107,8 +103,8 @@ class ManualFillingBridge {
}
@CalledByNative
private static Object addUserInfoToAccessorySheetData(Object objAccessorySheetData) {
UserInfo userInfo = new UserInfo();
private Object addUserInfoToAccessorySheetData(Object objAccessorySheetData) {
UserInfo userInfo = new UserInfo(this::fetchFavicon);
((AccessorySheetData) objAccessorySheetData).getUserInfoList().add(userInfo);
return userInfo;
}
......@@ -143,51 +139,6 @@ class ManualFillingBridge {
}));
}
private Item[] convertToItems(AccessorySheetData accessorySheetData) {
List<Item> items = new ArrayList<>();
items.add(Item.createTopDivider());
items.add(Item.createLabel(accessorySheetData.getTitle(), accessorySheetData.getTitle()));
for (UserInfo userInfo : accessorySheetData.getUserInfoList()) {
for (UserInfo.Field field : userInfo.getFields()) {
Callback<Item> itemSelectedCallback = null;
if (field.isSelectable()) {
// TODO(crbug.com/902425): Create the callback in addFieldToUserInfo once the
// Item type is replaced with AccessorySheetData.
itemSelectedCallback = (item) -> {
assert mNativeView != 0 : "Controller was destroyed but the bridge wasn't!";
KeyboardAccessoryMetricsRecorder.recordSuggestionSelected(
AccessoryTabType.PASSWORDS,
item.isObfuscated() ? AccessorySuggestionType.PASSWORD
: AccessorySuggestionType.USERNAME);
nativeOnFillingTriggered(
mNativeView, item.isObfuscated(), item.getCaption());
};
}
// clang-format off
items.add(Item.createSuggestion(field.getDisplayText(), field.getA11yDescription(),
field.isObfuscated(), itemSelectedCallback, this::fetchFavicon));
// clang-format on
}
}
if (!accessorySheetData.getFooterCommands().isEmpty()) {
items.add(Item.createDivider());
for (FooterCommand footerCommand : accessorySheetData.getFooterCommands()) {
items.add(Item.createOption(
footerCommand.getDisplayText(), footerCommand.getDisplayText(), (item) -> {
assert mNativeView
!= 0 : "Controller was destroyed but the bridge wasn't!";
nativeOnOptionSelected(mNativeView, item.getCaption());
}));
}
}
return items.toArray(new Item[items.size()]);
}
public void fetchFavicon(@Px int desiredSize, Callback<Bitmap> faviconCallback) {
assert mNativeView != 0 : "Favicon was requested after the bridge was destroyed!";
nativeOnFaviconRequested(mNativeView, desiredSize, faviconCallback);
......
......@@ -103,8 +103,9 @@ public class ManualFillingCoordinator {
mMediator.registerActionProvider(actionProvider);
}
void registerPasswordProvider(Provider<KeyboardAccessoryData.Item[]> itemProvider) {
mMediator.registerPasswordProvider(itemProvider);
void registerPasswordProvider(
Provider<KeyboardAccessoryData.AccessorySheetData> sheetDataProvider) {
mMediator.registerPasswordProvider(sheetDataProvider);
}
public void showWhenKeyboardIsVisible() {
......
......@@ -220,10 +220,10 @@ class ManualFillingMediator extends EmptyTabObserver
}
}
void registerPasswordProvider(Provider<KeyboardAccessoryData.Item[]> itemProvider) {
void registerPasswordProvider(Provider<KeyboardAccessoryData.AccessorySheetData> dataProvider) {
PasswordAccessorySheetCoordinator accessorySheet = getPasswordAccessorySheet();
if (accessorySheet == null) return; // Not available or initialized yet.
accessorySheet.registerItemProvider(itemProvider);
accessorySheet.registerDataProvider(dataProvider);
}
void registerActionProvider(KeyboardAccessoryData.PropertyProvider<Action[]> actionProvider) {
......
......@@ -106,10 +106,11 @@ public class PasswordAccessorySheetCoordinator implements KeyboardAccessoryData.
/**
* Registered item providers can replace the currently shown data in the password sheet.
* @param itemProvider The provider this component will listen to.
* @param dataProvider The provider this component will listen to.
*/
public void registerItemProvider(KeyboardAccessoryData.Provider<Item[]> itemProvider) {
itemProvider.addObserver(mMediator);
public void registerDataProvider(
KeyboardAccessoryData.Provider<KeyboardAccessoryData.AccessorySheetData> dataProvider) {
dataProvider.addObserver(mMediator);
}
/**
......
......@@ -11,22 +11,27 @@ import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo;
import org.chromium.chrome.browser.modelutil.ListModel;
import org.chromium.chrome.browser.modelutil.PropertyModel;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
import java.util.ArrayList;
import java.util.List;
/**
* This class contains all logic for the password accessory sheet component. Changes to its internal
* {@link PropertyModel} are observed by a {@link PropertyModelChangeProcessor} and affect the
* {@link PasswordAccessorySheetView}.
*/
class PasswordAccessorySheetMediator implements KeyboardAccessoryData.Observer<Item[]> {
class PasswordAccessorySheetMediator implements KeyboardAccessoryData.Observer<AccessorySheetData> {
private final PropertyModel mModel;
@Override
public void onItemAvailable(int typeId, Item[] items) {
mModel.get(CREDENTIALS).set(items);
public void onItemAvailable(int typeId, AccessorySheetData accessorySheetData) {
mModel.get(CREDENTIALS).set(convertToItems(accessorySheetData));
}
PasswordAccessorySheetMediator(
......@@ -41,6 +46,31 @@ class PasswordAccessorySheetMediator implements KeyboardAccessoryData.Observer<I
AccessoryTabType.PASSWORDS, mModel.get(CREDENTIALS));
}
private Item[] convertToItems(AccessorySheetData accessorySheetData) {
if (accessorySheetData == null) return new Item[0];
List<Item> items = new ArrayList<>();
items.add(Item.createTopDivider());
items.add(Item.createLabel(accessorySheetData.getTitle(), accessorySheetData.getTitle()));
for (UserInfo userInfo : accessorySheetData.getUserInfoList()) {
for (UserInfo.Field field : userInfo.getFields()) {
items.add(Item.createSuggestion(field.getDisplayText(), field.getA11yDescription(),
field.isObfuscated(),
item -> field.triggerSelection(), userInfo.getFaviconProvider()));
}
}
if (!accessorySheetData.getFooterCommands().isEmpty()) items.add(Item.createDivider());
for (KeyboardAccessoryData.FooterCommand command : accessorySheetData.getFooterCommands()) {
items.add(Item.createOption(
command.getDisplayText(), command.getDisplayText(), (i) -> command.execute()));
}
return items.toArray(new Item[0]);
}
@VisibleForTesting
ListModel<Item> getModelForTesting() {
return mModel.get(CREDENTIALS);
......
......@@ -18,7 +18,7 @@ import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertNotNull;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.TEST_CREDENTIALS;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.createTestCredentials;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
......@@ -107,7 +107,7 @@ public class ManualFillingIntegrationTest {
// Focus the field to bring up the accessory.
onView(withId(R.id.keyboard_accessory)).check(doesNotExist());
mHelper.clickPasswordField();
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
mHelper.waitForKeyboard();
// Check that ONLY the accessory is there but the sheet is still hidden.
......@@ -123,7 +123,7 @@ public class ManualFillingIntegrationTest {
// Focus the field to bring up the accessory.
mHelper.clickPasswordField();
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
mHelper.waitForKeyboard();
whenDisplayed(withId(R.id.keyboard_accessory));
......@@ -352,7 +352,7 @@ public class ManualFillingIntegrationTest {
});
listener.addInfoBarAnimationFinished("InfoBar not added.");
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
whenDisplayed(withText(kInfoBarText));
// Focus the field to bring up the accessory.
......@@ -393,7 +393,7 @@ public class ManualFillingIntegrationTest {
});
listener.addInfoBarAnimationFinished("InfoBar not added.");
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
whenDisplayed(withText(kInfoBarText));
// Focus the field to bring up the accessory.
......@@ -472,7 +472,7 @@ public class ManualFillingIntegrationTest {
});
listener.addInfoBarAnimationFinished("InfoBar not added.");
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
assertThat(mActivityTestRule.getInfoBarContainer().getVisibility(), is(View.VISIBLE));
// Focus the field to bring up the accessory.
......
......@@ -18,6 +18,7 @@ import static org.chromium.chrome.test.util.ViewUtils.waitForView;
import static org.chromium.ui.base.LocalizationUtils.setRtlForTesting;
import android.app.Activity;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.test.espresso.PerformException;
import android.support.test.espresso.UiController;
......@@ -30,13 +31,16 @@ import android.view.ViewGroup;
import org.hamcrest.Matcher;
import org.junit.Assert;
import org.chromium.base.Callback;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.UrlUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.ChromeWindow;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.FooterCommand;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Provider;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.content_public.browser.ImeAdapter;
import org.chromium.content_public.browser.WebContents;
......@@ -54,17 +58,10 @@ import java.util.concurrent.atomic.AtomicReference;
* Helpers in this class simplify interactions with the Keyboard Accessory and the sheet below it.
*/
public class ManualFillingTestHelper {
public static final Item[] TEST_CREDENTIALS = new Item[] {Item.createTopDivider(),
Item.createLabel("Saved passwords for this site", ""),
Item.createSuggestion("mpark@gmail.com", "", false, (item) -> {}, null),
Item.createSuggestion("TestPassword", "", true, (item) -> {}, null),
Item.createSuggestion("mayapark@googlemail.com", "", false, (item) -> {}, null),
Item.createSuggestion("SomeReallyLongPassword", "", true, (item) -> {}, null),
Item.createDivider(), Item.createOption("Manage Passwords...", "", (item) -> {})};
private final ChromeTabbedActivityTestRule mActivityTestRule;
private final AtomicReference<WebContents> mWebContentsRef = new AtomicReference<>();
private TestInputMethodManagerWrapper mInputMethodManagerWrapper;
private Provider<Item[]> mSheetSuggestionsProvider =
private Provider<AccessorySheetData> mSheetSuggestionsProvider =
new KeyboardAccessoryData.PropertyProvider<>();
public FakeKeyboard getKeyboard() {
......@@ -105,9 +102,7 @@ public class ManualFillingTestHelper {
mSheetSuggestionsProvider);
});
DOMUtils.waitForNonZeroNodeBounds(mWebContentsRef.get(), "password");
sendCredentials(new Item[] {Item.createTopDivider(),
Item.createLabel("No Saved passwords for this site", ""), Item.createDivider(),
Item.createOption("Manage Passwords...", "", (item) -> {})});
sendCredentials(createEmptyCredentials());
}
public void clear() {
......@@ -192,7 +187,7 @@ public class ManualFillingTestHelper {
/**
* Creates and adds a password tab to keyboard accessory and sheet.
*/
public void sendCredentials(Item[] testCrendentials) {
public void sendCredentials(AccessorySheetData testCrendentials) {
ThreadUtils.runOnUiThreadBlocking(
() -> { mSheetSuggestionsProvider.notifyObservers(testCrendentials); });
}
......@@ -327,4 +322,35 @@ public class ManualFillingTestHelper {
"Marcus", AccessoryAction.AUTOFILL_SUGGESTION, result -> {})});
});
}
public static AccessorySheetData createTestCredentials() {
AccessorySheetData testCredentials =
new AccessorySheetData("Saved passwords for this site");
testCredentials.getUserInfoList().add(createUserInfo("mpark@gmail.com", "TestPassword"));
testCredentials.getUserInfoList().add(
createUserInfo("mayapark@googlemail.com", "SomeReallyLongPassword"));
testCredentials.getFooterCommands().add(
new FooterCommand("Manage Passwords...", (item) -> {}));
return testCredentials;
}
public static AccessorySheetData createEmptyCredentials() {
AccessorySheetData testCredentials =
new AccessorySheetData("No Saved passwords for this site");
testCredentials.getFooterCommands().add(
new FooterCommand("Manage Passwords...", (item) -> {}));
return testCredentials;
}
public static UserInfo createUserInfo(String username, String password) {
return createUserInfo(username, password, null);
}
public static UserInfo createUserInfo(
String username, String password, @Nullable Callback<UserInfo.Field> userCallback) {
UserInfo info = new UserInfo(null);
info.addField(new UserInfo.Field(username, username, false, userCallback));
info.addField(new UserInfo.Field(password, "Password for " + username, true, result -> {}));
return info;
}
}
......@@ -9,7 +9,7 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.TEST_CREDENTIALS;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.createTestCredentials;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.scrollToLastElement;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
......@@ -75,13 +75,13 @@ public class ManualFillingUiCaptureTest {
mHelper.addGenerationButton();
mHelper.clickPasswordField();
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
waitForActionsInAccessory();
waitForUnrelatedChromeUi();
mScreenShooter.shoot("AccessoryBar");
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
whenDisplayed(withId(R.id.tabs)).perform(selectTabAtPosition(0));
waitForSuggestionsInSheet();
......@@ -103,13 +103,13 @@ public class ManualFillingUiCaptureTest {
mHelper.loadTestPage(true);
mHelper.addGenerationButton();
mHelper.clickPasswordField();
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
waitForActionsInAccessory();
waitForUnrelatedChromeUi();
mScreenShooter.shoot("AccessoryBarRTL");
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
whenDisplayed(withId(R.id.tabs)).perform(selectTabAtPosition(0));
waitForSuggestionsInSheet();
......@@ -132,13 +132,13 @@ public class ManualFillingUiCaptureTest {
mHelper.addGenerationButton();
mHelper.clickPasswordField();
mHelper.addAutofillChips();
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
waitForActionsInAccessory();
waitForUnrelatedChromeUi();
mScreenShooter.shoot("AccessoryBarV2");
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
whenDisplayed(withId(R.id.tabs)).perform(selectTabAtPosition(0));
waitForSuggestionsInSheet();
......@@ -161,13 +161,13 @@ public class ManualFillingUiCaptureTest {
mHelper.addGenerationButton();
mHelper.clickPasswordField();
mHelper.addAutofillChips();
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
waitForActionsInAccessory();
waitForUnrelatedChromeUi();
mScreenShooter.shoot("AccessoryBarV2RTL");
mHelper.sendCredentials(TEST_CREDENTIALS);
mHelper.sendCredentials(createTestCredentials());
whenDisplayed(withId(R.id.tabs)).perform(selectTabAtPosition(0));
waitForSuggestionsInSheet();
......
......@@ -18,6 +18,7 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.createUserInfo;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
......@@ -37,14 +38,15 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.Callback;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.FlakyTest;
import org.chromium.base.test.util.RetryOnFailure;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.FooterCommand;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo.Field;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.browser.Features;
......@@ -128,11 +130,14 @@ public class PasswordAccessoryIntegrationTest {
public void testPasswordSheetDisplaysProvidedItems()
throws InterruptedException, TimeoutException {
mHelper.loadTestPage(false);
mHelper.sendCredentials(new Item[] {Item.createLabel("Passwords", "Description_Passwords"),
createSuggestion("mayapark@gmail.com", (item) -> {}),
createPassword("SomeHiddenPassword"),
createSuggestion("mayaelisabethmercedesgreenepark@googlemail.com", (item) -> {}),
createPassword("ExtremelyLongPasswordThatUsesQuiteSomeSpaceInTheSheet")});
AccessorySheetData accessorySheetData = new AccessorySheetData("Passwords");
accessorySheetData.getUserInfoList().add(
createUserInfo("mayapark@gmail.com", "SomeHiddenPassword"));
accessorySheetData.getUserInfoList().add(
createUserInfo("mayaelisabethmercedesgreenepark@googlemail.com",
"ExtremelyLongPasswordThatUsesQuiteSomeSpaceInTheSheet"));
mHelper.sendCredentials(accessorySheetData);
// Focus the field to bring up the accessory.
mHelper.clickPasswordField();
......@@ -153,13 +158,14 @@ public class PasswordAccessoryIntegrationTest {
public void testPasswordSheetDisplaysNoPasswordsMessageAndOptions()
throws InterruptedException, TimeoutException {
mHelper.loadTestPage(false);
final AtomicReference<Item> clicked = new AtomicReference<>();
mHelper.sendCredentials(new Item[] {
Item.createLabel("No saved passwords for abc.com", "Description_Passwords"),
Item.createDivider(),
Item.createOption(
"Suggest strong password...", "Description_Generate", clicked::set),
Item.createOption("Manage passwords...", "Description_Manage", (item) -> {})});
final AtomicReference<FooterCommand> clicked = new AtomicReference<>();
AccessorySheetData accessorySheetData =
new AccessorySheetData("No saved passwords for abc.com");
accessorySheetData.getFooterCommands().add(
new FooterCommand("Suggest strong password...", clicked::set));
accessorySheetData.getFooterCommands().add(
new FooterCommand("Manage passwords...", clicked::set));
mHelper.sendCredentials(accessorySheetData);
// Focus the field to bring up the accessory.
mHelper.clickPasswordField();
......@@ -173,7 +179,7 @@ public class PasswordAccessoryIntegrationTest {
// The callback should have triggered and set the reference to the selected Item.
assertThat(clicked.get(), notNullValue());
assertThat(clicked.get().getCaption(), equalTo("Suggest strong password..."));
assertThat(clicked.get().getDisplayText(), equalTo("Suggest strong password..."));
}
@Test
......@@ -182,18 +188,16 @@ public class PasswordAccessoryIntegrationTest {
@FlakyTest(message = "crbug.com/855617")
public void testPasswordSheetTriggersCallback() throws InterruptedException, TimeoutException {
mHelper.loadTestPage(false);
final AtomicReference<Item> clicked = new AtomicReference<>();
mHelper.sendCredentials(new Item[] {
Item.createLabel("Passwords", "Description_Passwords"),
createSuggestion("mpark@abc.com", null),
createPassword("ShorterPassword"),
createSuggestion("mayap@xyz.com", null),
createPassword("PWD"),
createSuggestion("park@googlemail.com", null),
createPassword("P@$$W0rt"),
createSuggestion("mayapark@gmail.com", clicked::set),
createPassword("SomeHiddenLongPassword"),
});
final AtomicReference<Field> clicked = new AtomicReference<>();
AccessorySheetData accessorySheetData = new AccessorySheetData("Passwords");
accessorySheetData.getUserInfoList().add(
createUserInfo("mpark@abc.com", "ShorterPassword"));
accessorySheetData.getUserInfoList().add(createUserInfo("mayap@xyz.com", "PWD"));
accessorySheetData.getUserInfoList().add(createUserInfo("park@googlemail.com", "P@$$W0rt"));
accessorySheetData.getUserInfoList().add(
createUserInfo("mayapark@gmail.com", "SomeHiddenLongPassword", clicked::set));
mHelper.sendCredentials(accessorySheetData);
// Focus the field to bring up the accessory.
mHelper.clickPasswordField();
......@@ -206,7 +210,7 @@ public class PasswordAccessoryIntegrationTest {
// The callback should have triggered and set the reference to the selected Item.
assertThat(clicked.get(), notNullValue());
assertThat(clicked.get().getCaption(), equalTo("mayapark@gmail.com"));
assertThat(clicked.get().getDisplayText(), equalTo("mayapark@gmail.com"));
}
@Test
......@@ -250,12 +254,4 @@ public class PasswordAccessoryIntegrationTest {
}
};
}
private static Item createSuggestion(String caption, Callback<Item> callback) {
return Item.createSuggestion(caption, "Description_" + caption, false, callback, null);
}
private static Item createPassword(String caption) {
return Item.createSuggestion(caption, "Description_" + caption, true, null, null);
}
}
......@@ -45,10 +45,11 @@ import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeKeyboardVisibilityDelegate;
import org.chromium.chrome.browser.ChromeWindow;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Action;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.PropertyProvider;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Provider;
import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
import org.chromium.chrome.browser.modelutil.ListModel;
import org.chromium.chrome.browser.modelutil.ListObservable;
......@@ -184,34 +185,29 @@ public class ManualFillingControllerTest {
@Test
public void testPasswordItemsPersistAfterSwitchingBrowserTabs() {
ManualFillingMediator mediator = mController.getMediatorForTesting();
Provider<Item[]> firstTabProvider = new PropertyProvider<>();
Provider<Item[]> secondTabProvider = new PropertyProvider<>();
Provider<AccessorySheetData> firstTabProvider = new PropertyProvider<>();
Provider<AccessorySheetData> secondTabProvider = new PropertyProvider<>();
// Simulate opening a new tab which automatically triggers the registration:
Tab firstTab = addTab(mediator, 1111, null);
mController.registerPasswordProvider(firstTabProvider);
firstTabProvider.notifyObservers(new Item[] {
Item.createSuggestion("FirstPassword", "FirstPassword", true, result -> {}, null)});
assertThat(mediator.getPasswordAccessorySheet().getModelForTesting().get(0).getCaption(),
is("FirstPassword"));
firstTabProvider.notifyObservers(createPasswordData("FirstPassword"));
assertThat(getFirstPassword(mediator), is("FirstPassword"));
// Simulate creating a second tab:
Tab secondTab = addTab(mediator, 2222, firstTab);
mController.registerPasswordProvider(secondTabProvider);
secondTabProvider.notifyObservers(new Item[] {Item.createSuggestion(
"SecondPassword", "SecondPassword", true, result -> {}, null)});
assertThat(mediator.getPasswordAccessorySheet().getModelForTesting().get(0).getCaption(),
is("SecondPassword"));
secondTabProvider.notifyObservers(createPasswordData("SecondPassword"));
assertThat(getFirstPassword(mediator), is("SecondPassword"));
// Simulate switching back to the first tab:
switchTab(mediator, /*from=*/secondTab, /*to=*/firstTab);
assertThat(mediator.getPasswordAccessorySheet().getModelForTesting().get(0).getCaption(),
is("FirstPassword"));
assertThat(getFirstPassword(mediator), is("FirstPassword"));
// And back to the second:
switchTab(mediator, /*from=*/firstTab, /*to=*/secondTab);
assertThat(mediator.getPasswordAccessorySheet().getModelForTesting().get(0).getCaption(),
is("SecondPassword"));
assertThat(getFirstPassword(mediator), is("SecondPassword"));
}
@Test
......@@ -406,10 +402,10 @@ public class ManualFillingControllerTest {
.getMediatorForTesting()
.getModelForTesting();
Provider<Item[]> firstTabProvider = new PropertyProvider<>();
Provider<AccessorySheetData> firstTabProvider = new PropertyProvider<>();
PropertyProvider<Action[]> firstActionProvider =
new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
Provider<Item[]> secondTabProvider = new PropertyProvider<>();
Provider<AccessorySheetData> secondTabProvider = new PropertyProvider<>();
PropertyProvider<Action[]> secondActionProvider =
new PropertyProvider<>(GENERATE_PASSWORD_AUTOMATIC);
......@@ -417,8 +413,7 @@ public class ManualFillingControllerTest {
Tab firstTab = addTab(mediator, 1111, null);
mController.registerPasswordProvider(firstTabProvider);
mController.registerActionProvider(firstActionProvider);
firstTabProvider.notifyObservers(new Item[] {
Item.createSuggestion("FirstPassword", "FirstPassword", true, result -> {}, null)});
firstTabProvider.notifyObservers(createPasswordData("FirstPassword"));
firstActionProvider.notifyObservers(new Action[] {
new Action("2BDestroyed", GENERATE_PASSWORD_AUTOMATIC, (action) -> {})});
......@@ -426,8 +421,7 @@ public class ManualFillingControllerTest {
addTab(mediator, 2222, firstTab);
mController.registerPasswordProvider(secondTabProvider);
mController.registerActionProvider(secondActionProvider);
secondTabProvider.notifyObservers(new Item[] {Item.createSuggestion(
"SecondPassword", "SecondPassword", true, result -> {}, null)});
secondTabProvider.notifyObservers(createPasswordData("SecondPassword"));
secondActionProvider.notifyObservers(
new Action[] {new Action("2BKept", GENERATE_PASSWORD_AUTOMATIC, (action) -> {})});
......@@ -636,4 +630,21 @@ public class ManualFillingControllerTest {
mediator.onLayoutChange(
mMockContentView, 0, 0, newWidth, newHeight, 0, 0, oldWidth, oldHeight);
}
private AccessorySheetData createPasswordData(String text) {
AccessorySheetData sheetData = new AccessorySheetData("Passwords");
UserInfo userInfo = new UserInfo(null);
userInfo.addField(new UserInfo.Field("(No username)", "No username", false, null));
userInfo.addField(new UserInfo.Field(text, "Password", true, null));
sheetData.getUserInfoList().add(userInfo);
return sheetData;
}
private String getFirstPassword(ManualFillingMediator mediator) {
assert mediator.getPasswordAccessorySheet() != null;
assert mediator.getPasswordAccessorySheet().getModelForTesting() != null;
assert mediator.getPasswordAccessorySheet().getModelForTesting().size() > 1;
// The 0th item is a divider, the 1st a title, the 2nd a username and 3rd a password.
return mediator.getPasswordAccessorySheet().getModelForTesting().get(3).getCaption();
}
}
......@@ -75,32 +75,34 @@ public class PasswordAccessorySheetControllerTest {
@Test
public void testModelNotifiesAboutActionsChangedByProvider() {
final KeyboardAccessoryData.PropertyProvider<Item[]> testProvider =
final KeyboardAccessoryData
.PropertyProvider<KeyboardAccessoryData.AccessorySheetData> testProvider =
new KeyboardAccessoryData.PropertyProvider<>();
final Item testItem = Item.createLabel("Test Item", null);
final KeyboardAccessoryData.AccessorySheetData testData =
new KeyboardAccessoryData.AccessorySheetData("Passwords");
mModel.addObserver(mMockItemListObserver);
mCoordinator.registerItemProvider(testProvider);
mCoordinator.registerDataProvider(testProvider);
// If the coordinator receives an initial items, the model should report an insertion.
testProvider.notifyObservers(new Item[] {testItem});
verify(mMockItemListObserver).onItemRangeInserted(mModel, 0, 1);
assertThat(mModel.size(), is(1));
assertThat(mModel.get(0), is(equalTo(testItem)));
testProvider.notifyObservers(testData);
verify(mMockItemListObserver).onItemRangeInserted(mModel, 0, 2);
assertThat(mModel.size(), is(2));
assertThat(mModel.get(1).getCaption(), is(equalTo("Passwords")));
// If the coordinator receives a new set of items, the model should report a change.
testProvider.notifyObservers(new Item[] {testItem});
verify(mMockItemListObserver).onItemRangeChanged(mModel, 0, 1, null);
assertThat(mModel.size(), is(1));
assertThat(mModel.get(0), is(equalTo(testItem)));
testProvider.notifyObservers(testData);
verify(mMockItemListObserver).onItemRangeChanged(mModel, 0, 2, null);
assertThat(mModel.size(), is(2));
assertThat(mModel.get(1).getCaption(), is(equalTo("Passwords")));
// If the coordinator receives an empty set of items, the model should report a deletion.
testProvider.notifyObservers(new Item[] {});
verify(mMockItemListObserver).onItemRangeRemoved(mModel, 0, 1);
testProvider.notifyObservers(null);
verify(mMockItemListObserver).onItemRangeRemoved(mModel, 0, 2);
assertThat(mModel.size(), is(0));
// There should be no notification if no item are reported repeatedly.
testProvider.notifyObservers(new Item[] {});
testProvider.notifyObservers(null);
verifyNoMoreInteractions(mMockItemListObserver);
}
......
......@@ -139,8 +139,8 @@ ManualFillingViewAndroid::ConvertAccessorySheetDataToJavaObject(
for (const UserInfo& user_info : tab_data.user_info_list()) {
ScopedJavaLocalRef<jobject> j_user_info =
Java_ManualFillingBridge_addUserInfoToAccessorySheetData(env,
j_tab_data);
Java_ManualFillingBridge_addUserInfoToAccessorySheetData(
env, java_object_, j_tab_data);
for (const UserInfo::Field& field : user_info.fields()) {
Java_ManualFillingBridge_addFieldToUserInfo(
env, java_object_, j_user_info,
......
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