Commit 0f8ca10f authored by Reda Tawfik's avatar Reda Tawfik Committed by Commit Bot

[Android][Mfill] Add a controller for AllPasswordsBottomSheet

This Cl adds the controller and the model for AllPasswordsBottomSheet
and sends the credentials from the bridge to the coordinator to
the mediator.
Adds a unit test for the controller.

Bug: 1104132
Change-Id: I5a56ea9d3095cad29fed19a058805ed0121be47c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2317797
Commit-Queue: Reda Tawfik <redatawfik@noogler.google.com>
Reviewed-by: default avatarIoana Pandele <ioanap@chromium.org>
Reviewed-by: default avatarFriedrich [CET] <fhorschig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799649}
parent a382113d
......@@ -95,6 +95,7 @@ junit_binary("keyboard_accessory_junit_tests") {
sources = [
"junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java",
"junit/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetControllerTest.java",
"junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java",
"junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetControllerTest.java",
"junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetControllerTest.java",
......
......@@ -47,6 +47,9 @@ android_library("internal_java") {
"java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingState.java",
"java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingStateCache.java",
"java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetBridge.java",
"java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetCoordinator.java",
"java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMediator.java",
"java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetProperties.java",
"java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/Credential.java",
"java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java",
"java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java",
......
......@@ -6,19 +6,25 @@ package org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_shee
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
import org.chromium.ui.base.WindowAndroid;
/**
* This bridge creates and initializes a {@link AllPasswordsBottomSheetCoordinator} on construction
* and forwards native calls to it.
*/
class AllPasswordsBottomSheetBridge {
class AllPasswordsBottomSheetBridge implements AllPasswordsBottomSheetCoordinator.Delegate {
private long mNativeView;
private Credential[] mCredentials;
private final AllPasswordsBottomSheetCoordinator mAllPasswordsBottomSheetCoordinator;
private AllPasswordsBottomSheetBridge(long nativeView, WindowAndroid windowAndroid) {
mNativeView = nativeView;
assert (mNativeView != 0);
assert (windowAndroid.getActivity().get() != null);
mAllPasswordsBottomSheetCoordinator = new AllPasswordsBottomSheetCoordinator();
mAllPasswordsBottomSheetCoordinator.initialize(windowAndroid.getActivity().get(),
BottomSheetControllerProvider.from(windowAndroid), this);
}
@CalledByNative
......@@ -47,9 +53,20 @@ class AllPasswordsBottomSheetBridge {
@CalledByNative
private void showCredentials() {
// TODO(crbug.com/1104132): Implement.
// Temporary call to deleted native objects and avoid memory leak.
AllPasswordsBottomSheetBridgeJni.get().onDismiss(mNativeView);
mAllPasswordsBottomSheetCoordinator.showCredentials(mCredentials);
}
@Override
public void onCredentialSelected(Credential credential) {
assert mNativeView != 0 : "The native side is already dismissed";
AllPasswordsBottomSheetBridgeJni.get().onCredentialSelected(mNativeView, credential);
}
@Override
public void onDismissed() {
if (mNativeView != 0) {
AllPasswordsBottomSheetBridgeJni.get().onDismiss(mNativeView);
}
}
@NativeMethods
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet;
import android.content.Context;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.ui.modelutil.PropertyModel;
/**
* Creates the AllPasswordsBottomSheet. AllPasswordsBottomSheet uses a bottom sheet to let the
* user select a credential and fills it into the focused form.
*/
class AllPasswordsBottomSheetCoordinator {
private final AllPasswordsBottomSheetMediator mMediator = new AllPasswordsBottomSheetMediator();
private final PropertyModel mModel =
AllPasswordsBottomSheetProperties.createDefaultModel(mMediator::onDismissed);
/**
* This delegate is called when the AllPasswordsBottomSheet is interacted with (e.g. dismissed
* or a suggestion was selected).
*/
interface Delegate {
/**
* Called when the user selects one of the credentials shown in the AllPasswordsBottomSheet.
*/
void onCredentialSelected(Credential credential);
/**
* Called when the user dismisses the AllPasswordsBottomSheet. Not called if a suggestion
* was selected.
*/
void onDismissed();
}
/**
* Initializes the component.
* @param context A {@link Context} to create views and retrieve resources.
* @param sheetController A {@link BottomSheetController} used to show/hide the sheet.
* @param delegate A {@link Delegate} that handles dismiss events.
*/
public void initialize(Context context, BottomSheetController sheetController,
AllPasswordsBottomSheetCoordinator.Delegate delegate) {
mMediator.initialize(delegate, mModel);
}
/**
* Displays the given credentials in a new bottom sheet.
* @param credentials An array of {@link Credential}s that will be displayed.
*/
public void showCredentials(Credential[] credentials) {
mMediator.showCredentials(credentials);
}
}
\ No newline at end of file
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet;
import org.chromium.ui.modelutil.PropertyModel;
/**
* Contains the logic for the AllPasswordsBottomSheet. It sets the state of the model and reacts to
* events like clicks.
*/
class AllPasswordsBottomSheetMediator {
private AllPasswordsBottomSheetCoordinator.Delegate mDelegate;
private PropertyModel mModel;
void initialize(AllPasswordsBottomSheetCoordinator.Delegate delegate, PropertyModel model) {
assert delegate != null;
mDelegate = delegate;
mModel = model;
}
void showCredentials(Credential[] credentials) {
assert credentials != null;
// Temporary call to destroy native objects to avoid memory leak.
mDelegate.onDismissed();
}
void onDismissed(Integer integer) {
mDelegate.onDismissed();
}
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet;
import org.chromium.base.Callback;
import org.chromium.ui.modelutil.ListModel;
import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
import org.chromium.ui.modelutil.PropertyModel;
/**
* Properties defined here reflect the visible state of the AllPasswordsBottomSheet.
*/
class AllPasswordsBottomSheetProperties {
static final PropertyModel.WritableBooleanPropertyKey VISIBLE =
new PropertyModel.WritableBooleanPropertyKey("visible");
static final PropertyModel.ReadableObjectPropertyKey<Callback<Integer>> DISMISS_HANDLER =
new PropertyModel.ReadableObjectPropertyKey<>("dismiss_handler");
static final PropertyModel.ReadableObjectPropertyKey<ListModel<ListItem>> SHEET_ITEMS =
new PropertyModel.ReadableObjectPropertyKey<>("sheet_items");
static PropertyModel createDefaultModel(Callback<Integer> handler) {
return new PropertyModel.Builder(VISIBLE, SHEET_ITEMS, DISMISS_HANDLER)
.with(VISIBLE, false)
.with(SHEET_ITEMS, new ListModel<>())
.with(DISMISS_HANDLER, handler)
.build();
}
}
......@@ -7,9 +7,10 @@ package org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_shee
import org.chromium.base.annotations.CalledByNative;
/**
* This class holds the data used to represent a selectable credential in the All Passwords sheet.
* This class holds the data used to represent a selectable credential in the
* AllPasswordsBottomSheet.
*/
public class Credential {
class Credential {
private final String mUsername;
private final String mPassword;
private final String mFormattedUsername;
......@@ -25,7 +26,7 @@ public class Credential {
* @param isAffiliationBasedMatch Indicating whether the credential is an affiliation based
* match (i.e. whether it is an Android credential).
*/
public Credential(String username, String password, String formattedUsername, String originUrl,
Credential(String username, String password, String formattedUsername, String originUrl,
boolean isPublicSuffixMatch, boolean isAffiliationBasedMatch) {
assert originUrl != null : "Credential origin is null! Pass an empty one instead.";
mUsername = username;
......@@ -37,31 +38,31 @@ public class Credential {
}
@CalledByNative
public String getUsername() {
String getUsername() {
return mUsername;
}
@CalledByNative
public String getPassword() {
String getPassword() {
return mPassword;
}
public String getFormattedUsername() {
String getFormattedUsername() {
return mFormattedUsername;
}
@CalledByNative
public String getOriginUrl() {
String getOriginUrl() {
return mOriginUrl;
}
@CalledByNative
public boolean isPublicSuffixMatch() {
boolean isPublicSuffixMatch() {
return mIsPublicSuffixMatch;
}
@CalledByNative
public boolean isAffiliationBasedMatch() {
boolean isAffiliationBasedMatch() {
return mIsAffiliationBasedMatch;
}
}
\ No newline at end of file
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.verify;
import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetProperties.DISMISS_HANDLER;
import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetProperties.SHEET_ITEMS;
import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetProperties.VISIBLE;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.ui.modelutil.PropertyModel;
/**
* Controller tests for the all passwords bottom sheet.
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
@Features.EnableFeatures(ChromeFeatureList.FILLING_PASSWORDS_FROM_ANY_ORIGIN)
public class AllPasswordsBottomSheetControllerTest {
@Mock
private AllPasswordsBottomSheetCoordinator.Delegate mMockDelegate;
private final AllPasswordsBottomSheetMediator mMediator = new AllPasswordsBottomSheetMediator();
private PropertyModel mModel;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mModel = AllPasswordsBottomSheetProperties.createDefaultModel(mMediator::onDismissed);
mMediator.initialize(mMockDelegate, mModel);
}
@Test
public void testCreatesValidDefaultModel() {
assertNotNull(mModel.get(SHEET_ITEMS));
assertNotNull(mModel.get(DISMISS_HANDLER));
assertThat(mModel.get(VISIBLE), is(false));
}
@Test
public void testCallsDelegateOnDismiss() {
mMediator.onDismissed(BottomSheetController.StateChangeReason.BACK_PRESS);
verify(mMockDelegate).onDismissed();
}
}
......@@ -66,7 +66,9 @@ gfx::NativeView AllPasswordsBottomSheetController::GetNativeView() {
void AllPasswordsBottomSheetController::OnCredentialSelected(
const UiCredential& credential) {
driver_->FillSuggestion(credential.username(), credential.password());
// TODO(crbug.com/1104132): Call OnDismiss().
// Consumes the dismissal callback to destroy the native controller and java
// controller after the user selects a credential.
OnDismiss();
}
void AllPasswordsBottomSheetController::OnDismiss() {
......
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