Commit 1ee287cf authored by Friedrich Horschig's avatar Friedrich Horschig Committed by Commit Bot

Introduce component scaffold for accessory sheets

This CL introduces the sheet that can replace the keyboard if triggered
by the keyboard accessory.

Beyond showing or hiding, it has no functionality yet.
The next steps will introduce the layout for passwords as started in
https://crrev.com/c/951588. The latter CL is deprecated with this CL.

The minimalist root component only simplifies testing at this point.

Bug: 811747
Change-Id: I2aaa2b5c3fbf782866301125f5a81307165efbfe
Reviewed-on: https://chromium-review.googlesource.com/1030551
Commit-Queue: Friedrich Horschig <fhorschig@chromium.org>
Reviewed-by: default avatarBernhard Bauer <bauerb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#556032}
parent a7c471b4
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 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. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keyboard_accessory"
android:background="@drawable/keyboard_accessory_background"
android:contentDescription="@string/autofill_keyboard_accessory_content_description"
android:fillViewport="true"
android:layout_gravity="start|bottom"
android:layout_height="@dimen/keyboard_accessory_sheet_height"
android:layout_width="match_parent"
android:orientation="vertical"
android:visibility="gone"/>
\ No newline at end of file
...@@ -34,6 +34,13 @@ ...@@ -34,6 +34,13 @@
android:layout_height="@dimen/keyboard_accessory_height" android:layout_height="@dimen/keyboard_accessory_height"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_gravity="start|bottom"/> android:layout_gravity="start|bottom"/>
<ViewStub
android:id="@+id/keyboard_accessory_sheet_stub"
android:inflatedId="@+id/keyboard_accessory"
android:layout="@layout/keyboard_accessory_sheet"
android:layout_height="@dimen/keyboard_accessory_sheet_height"
android:layout_width="match_parent"
android:layout_gravity="start|bottom"/>
</org.chromium.chrome.browser.snackbar.BottomContainer> </org.chromium.chrome.browser.snackbar.BottomContainer>
......
...@@ -127,6 +127,7 @@ ...@@ -127,6 +127,7 @@
<dimen name="keyboard_accessory_half_padding">4dp</dimen> <dimen name="keyboard_accessory_half_padding">4dp</dimen>
<dimen name="keyboard_accessory_height">48dp</dimen> <dimen name="keyboard_accessory_height">48dp</dimen>
<dimen name="keyboard_accessory_padding">8dp</dimen> <dimen name="keyboard_accessory_padding">8dp</dimen>
<dimen name="keyboard_accessory_sheet_height">200dp</dimen>
<dimen name="keyboard_accessory_text_size">14sp</dimen> <dimen name="keyboard_accessory_text_size">14sp</dimen>
<!-- Password generation popup dimensions --> <!-- Password generation popup dimensions -->
......
// Copyright 2018 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.autofill.keyboard_accessory;
import android.view.ViewStub;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.modelutil.LazyViewBinderAdapter;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
/**
* Creates and owns all elements which are part of the accessory sheet component.
* It's part of the controller but will mainly forward events (like showing the sheet) and handle
* communication with the {@link ManualFillingController} (e.g. add a tab to trigger the sheet).
* to the {@link AccessorySheetMediator}.
*/
public class AccessorySheetCoordinator {
private final AccessorySheetMediator mMediator;
/**
* Creates the sheet component by instantiating Model, View and Controller before wiring these
* parts up.
* @param viewStub The view stub that can be inflated into the accessory layout.
*/
public AccessorySheetCoordinator(ViewStub viewStub) {
LazyViewBinderAdapter.StubHolder stubHolder =
new LazyViewBinderAdapter.StubHolder(viewStub);
AccessorySheetModel model = new AccessorySheetModel();
model.addObserver(new PropertyModelChangeProcessor<>(
model, stubHolder, new LazyViewBinderAdapter<>(new AccessorySheetViewBinder())));
mMediator = new AccessorySheetMediator(model);
}
/**
* Returns a {@link KeyboardAccessoryData.Tab} object that is used to display this bottom sheet.
* @return Returns a {@link KeyboardAccessoryData.Tab}.
*/
public KeyboardAccessoryData.Tab getTab() {
return mMediator.getTab();
}
@VisibleForTesting
AccessorySheetMediator getMediatorForTesting() {
return mMediator;
}
}
\ No newline at end of file
// Copyright 2018 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.autofill.keyboard_accessory;
import org.chromium.base.VisibleForTesting;
/**
* Contains the controller logic of the AccessorySheet component.
* It communicates with data providers and native backends to update a {@link AccessorySheetModel}.
*/
class AccessorySheetMediator {
private final AccessorySheetModel mModel;
private KeyboardAccessoryData.Tab mTab;
AccessorySheetMediator(AccessorySheetModel model) {
mModel = model;
}
KeyboardAccessoryData.Tab getTab() {
if (mTab == null) mTab = new KeyboardAccessoryData.Tab() {};
return mTab;
}
@VisibleForTesting
AccessorySheetModel getModelForTesting() {
return mModel;
}
public void show() {
mModel.setVisible(true);
}
public void hide() {
mModel.setVisible(false);
}
}
\ No newline at end of file
// Copyright 2018 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.autofill.keyboard_accessory;
import org.chromium.chrome.browser.modelutil.PropertyObservable;
/**
* This model holds all view state of the accessory sheet.
* It is updated by the {@link AccessorySheetMediator} and emits notification on which observers
* like the view binder react.
*/
class AccessorySheetModel extends PropertyObservable<AccessorySheetModel.PropertyKey> {
public static class PropertyKey { public static final PropertyKey VISIBLE = new PropertyKey(); }
private boolean mVisible;
public void setVisible(boolean visible) {
if (mVisible == visible) return; // Nothing to do here: same value.
mVisible = visible;
notifyPropertyChanged(PropertyKey.VISIBLE);
}
boolean isVisible() {
return mVisible;
}
}
\ No newline at end of file
// Copyright 2018 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.autofill.keyboard_accessory;
import android.view.View;
import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetModel.PropertyKey;
import org.chromium.chrome.browser.modelutil.LazyViewBinderAdapter;
/**
* Observes {@link AccessorySheetModel} changes (like a newly available tab) and triggers the
* {@link AccessorySheetViewBinder} which will modify the view accordingly.
*/
class AccessorySheetViewBinder
implements LazyViewBinderAdapter.SimpleViewBinder<PropertyKey, AccessorySheetModel> {
@Override
public PropertyKey getVisibilityProperty() {
return PropertyKey.VISIBLE;
}
@Override
public boolean isVisible(AccessorySheetModel model) {
return model.isVisible();
}
@Override
public void bind(AccessorySheetModel model, View inflatedView, PropertyKey propertyKey) {
if (propertyKey == PropertyKey.VISIBLE) {
inflatedView.setVisibility(model.isVisible() ? View.VISIBLE : View.GONE);
return;
}
assert false : "Every possible property update needs to be handled!";
}
}
// Copyright 2018 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.autofill.keyboard_accessory;
// TODO(fhorschig): Inline this class if the setting up/destroying is less overhead than expected.
// TODO(fhorschig): Otherwise, replace the KeyboardAccessorySheet in the ChromeActivity.
/**
* Handles requests to the manual UI for filling passwords, payments and other user data. Ideally,
* the caller has no access to Keyboard accessory or sheet and is only interacting with this
* component.
* For that, it facilitates the communication between {@link KeyboardAccessoryCoordinator} and
* {@link AccessorySheetCoordinator} to add and trigger surfaces that may assist users while filling
* fields.
*/
public class ManualFillingController {
private final KeyboardAccessoryCoordinator mKeyboardAccessoryCoordinator;
/**
* Creates a the manual filling controller.
* @param keyboardAccessoryCoordinator The keybaord
*/
public ManualFillingController(KeyboardAccessoryCoordinator keyboardAccessoryCoordinator) {
mKeyboardAccessoryCoordinator = keyboardAccessoryCoordinator;
}
/**
* Links an {@link AccessorySheetCoordinator} to the {@link KeyboardAccessoryCoordinator}.
* @param accessorySheetCoordinator The sheet component to be linked.
*/
public void addAccessorySheet(AccessorySheetCoordinator accessorySheetCoordinator) {
mKeyboardAccessoryCoordinator.addTab(accessorySheetCoordinator.getTab());
}
}
\ No newline at end of file
// Copyright 2018 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.modelutil;
import android.view.View;
import android.view.ViewStub;
import javax.annotation.Nullable;
/**
* Observes updates to a model {@link M} and calls a given {@link SimpleViewBinder} with a lazily
* inflated view whenever a property with key {@link K} has changed.
* The view used by this class is passed in as a {@link ViewStub} wrapped in a {@link StubHolder}.
* The held stub is inflated when the observed model becomes visible for the first time.
* @param <K> The type of property keys which are published by model {@link M}.
* @param <M> The observable model that contains the data which should be should to the view.
*/
public class LazyViewBinderAdapter<K, M extends PropertyObservable<K>>
implements PropertyModelChangeProcessor.ViewBinder<M, LazyViewBinderAdapter.StubHolder, K> {
/**
* Holds a {@link ViewStub} that is inflated by the {@link LazyViewBinderAdapter} which calls a
* {@link SimpleViewBinder}.
*/
public static class StubHolder {
@Nullable
private View mView; // Remains null until |mViewStub| is inflated.
private final ViewStub mViewStub;
public StubHolder(ViewStub viewStub) {
mViewStub = viewStub;
}
// TODO(fhorschig): Consider parameterizing this view.
@Nullable
public View getView() {
return mView;
}
void inflateView() {
mView = mViewStub.inflate();
}
}
/**
* A {@link PropertyModelChangeProcessor.ViewBinder} that provides information about when to
* inflate a viewStub managed by a {@link LazyViewBinderAdapter}.
* @param <K> The class of the properties that model {@link M} propagates.
* @param <M> The model holding data about the view and it's visibility.
*/
public interface SimpleViewBinder<K, M>
extends PropertyModelChangeProcessor.ViewBinder<M, View, K> {
/**
* @return The Property that will indicate when this component becomes visible.
*/
K getVisibilityProperty();
/**
* Returns whether this component should be visible now. The view binder will inflate the
* given stub if this returns true when the {@link SimpleViewBinder#getVisibilityProperty}
* is updated.
* @param model The model that should contain an observable property about the visibility.
* @return whether this component should be visible now.
*/
boolean isVisible(M model);
}
private final SimpleViewBinder<K, M> mBinder;
/**
* Creates the adapter with a {@link SimpleViewBinder} that will be used to determine when to
* inflate the {@link StubHolder} that is passed in by the {@link PropertyModelChangeProcessor}.
* @param binder The binder to be called with the fully inflated view.
*/
public LazyViewBinderAdapter(SimpleViewBinder<K, M> binder) {
mBinder = binder;
}
@Override
public void bind(M model, StubHolder stubHolder, K propertyKey) {
if (stubHolder.getView() == null) {
if (propertyKey != mBinder.getVisibilityProperty() || !mBinder.isVisible(model)) {
return; // Ignore model changes before the view is shown for the first time.
}
stubHolder.inflateView();
}
mBinder.bind(model, stubHolder.getView(), propertyKey);
}
}
...@@ -96,12 +96,17 @@ chrome_java_sources = [ ...@@ -96,12 +96,17 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/autofill/PasswordGenerationPopupBridge.java", "java/src/org/chromium/chrome/browser/autofill/PasswordGenerationPopupBridge.java",
"java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java", "java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java",
"java/src/org/chromium/chrome/browser/autofill/PhoneNumberUtil.java", "java/src/org/chromium/chrome/browser/autofill/PhoneNumberUtil.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetCoordinator.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetMediator.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetModel.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewBinder.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModel.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModel.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java",
"java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingController.java",
"java/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTask.java", "java/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTask.java",
"java/src/org/chromium/chrome/browser/banners/AppBannerManager.java", "java/src/org/chromium/chrome/browser/banners/AppBannerManager.java",
"java/src/org/chromium/chrome/browser/banners/AppBannerUiDelegateAndroid.java", "java/src/org/chromium/chrome/browser/banners/AppBannerUiDelegateAndroid.java",
...@@ -685,6 +690,7 @@ chrome_java_sources = [ ...@@ -685,6 +690,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java", "java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java",
"java/src/org/chromium/chrome/browser/modaldialog/TabModalLifetimeHandler.java", "java/src/org/chromium/chrome/browser/modaldialog/TabModalLifetimeHandler.java",
"java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java", "java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java",
"java/src/org/chromium/chrome/browser/modelutil/LazyViewBinderAdapter.java",
"java/src/org/chromium/chrome/browser/modelutil/ListObservable.java", "java/src/org/chromium/chrome/browser/modelutil/ListObservable.java",
"java/src/org/chromium/chrome/browser/modelutil/PropertyModelChangeProcessor.java", "java/src/org/chromium/chrome/browser/modelutil/PropertyModelChangeProcessor.java",
"java/src/org/chromium/chrome/browser/modelutil/PropertyObservable.java", "java/src/org/chromium/chrome/browser/modelutil/PropertyObservable.java",
...@@ -1558,6 +1564,7 @@ chrome_test_java_sources = [ ...@@ -1558,6 +1564,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java",
"javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java", "javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java",
"javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewTest.java", "javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewTest.java",
"javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewTest.java",
"javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java", "javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java",
"javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java", "javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java",
"javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java", "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java",
...@@ -1959,7 +1966,9 @@ chrome_junit_test_java_sources = [ ...@@ -1959,7 +1966,9 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/DisableHistogramsRule.java", "junit/src/org/chromium/chrome/browser/DisableHistogramsRule.java",
"junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java", "junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java",
"junit/src/org/chromium/chrome/browser/SSLClientCertificateRequestTest.java", "junit/src/org/chromium/chrome/browser/SSLClientCertificateRequestTest.java",
"junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetControllerTest.java",
"junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java", "junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java",
"junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java",
"junit/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTaskTest.java", "junit/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTaskTest.java",
"junit/src/org/chromium/chrome/browser/browseractions/BrowserActionsIntentTest.java", "junit/src/org/chromium/chrome/browser/browseractions/BrowserActionsIntentTest.java",
"junit/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimatorTest.java", "junit/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimatorTest.java",
......
// Copyright 2018 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.autofill.keyboard_accessory;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.support.test.filters.MediumTest;
import android.view.View;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.modelutil.LazyViewBinderAdapter;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
/**
* View tests for the keyboard accessory sheet component.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class AccessorySheetViewTest {
private AccessorySheetModel mModel;
private LazyViewBinderAdapter.StubHolder mStubHolder;
@Rule
public ChromeActivityTestRule<ChromeTabbedActivity> mActivityTestRule =
new ChromeActivityTestRule<>(ChromeTabbedActivity.class);
@Before
public void setUp() throws InterruptedException {
mActivityTestRule.startMainActivityOnBlankPage();
mStubHolder = new LazyViewBinderAdapter.StubHolder(
mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory_sheet_stub));
mModel = new AccessorySheetModel();
mModel.addObserver(new PropertyModelChangeProcessor<>(
mModel, mStubHolder, new LazyViewBinderAdapter<>(new AccessorySheetViewBinder())));
}
@Test
@MediumTest
public void testAccessoryVisibilityChangedByModel() {
// Initially, there shouldn't be a view yet.
assertNull(mStubHolder.getView());
// After setting the visibility to true, the view should exist and be visible.
ThreadUtils.runOnUiThreadBlocking(() -> mModel.setVisible(true));
assertNotNull(mStubHolder.getView());
assertTrue(mStubHolder.getView().getVisibility() == View.VISIBLE);
// After hiding the view, the view should still exist but be invisible.
ThreadUtils.runOnUiThreadBlocking(() -> mModel.setVisible(false));
assertNotNull(mStubHolder.getView());
assertTrue(mStubHolder.getView().getVisibility() != View.VISIBLE);
}
}
\ No newline at end of file
...@@ -9,8 +9,6 @@ import static junit.framework.Assert.assertNull; ...@@ -9,8 +9,6 @@ import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.chromium.chrome.R.id;
import android.support.test.filters.MediumTest; import android.support.test.filters.MediumTest;
import android.view.View; import android.view.View;
...@@ -21,6 +19,7 @@ import org.junit.runner.RunWith; ...@@ -21,6 +19,7 @@ import org.junit.runner.RunWith;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor; import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
...@@ -45,7 +44,7 @@ public class KeyboardAccessoryViewTest { ...@@ -45,7 +44,7 @@ public class KeyboardAccessoryViewTest {
public void setUp() throws InterruptedException { public void setUp() throws InterruptedException {
mActivityTestRule.startMainActivityOnBlankPage(); mActivityTestRule.startMainActivityOnBlankPage();
mViewHolder = new KeyboardAccessoryViewBinder.AccessoryViewHolder( mViewHolder = new KeyboardAccessoryViewBinder.AccessoryViewHolder(
mActivityTestRule.getActivity().findViewById(id.keyboard_accessory_stub)); mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory_stub));
mModel = new KeyboardAccessoryModel(); mModel = new KeyboardAccessoryModel();
mModel.addObserver(new PropertyModelChangeProcessor<>( mModel.addObserver(new PropertyModelChangeProcessor<>(
mModel, mViewHolder, new KeyboardAccessoryViewBinder())); mModel, mViewHolder, new KeyboardAccessoryViewBinder()));
......
// Copyright 2018 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.autofill.keyboard_accessory;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
import android.view.ViewStub;
import android.widget.LinearLayout;
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.base.test.util.Feature;
import org.chromium.chrome.browser.modelutil.PropertyObservable;
/**
* Controller tests for the keyboard accessory bottom sheet component.
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class AccessorySheetControllerTest {
@Mock
private PropertyObservable
.PropertyObserver<AccessorySheetModel.PropertyKey> mMockPropertyObserver;
@Mock
private ViewStub mMockViewStub;
@Mock
private LinearLayout mMockView;
private AccessorySheetCoordinator mCoordinator;
private AccessorySheetMediator mMediator;
private AccessorySheetModel mModel;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mMockViewStub.inflate()).thenReturn(mMockView);
mCoordinator = new AccessorySheetCoordinator(mMockViewStub);
mMediator = mCoordinator.getMediatorForTesting();
mModel = mMediator.getModelForTesting();
}
@Test
@SmallTest
public void testCreatesValidSubComponents() {
assertThat(mCoordinator, is(notNullValue()));
assertThat(mMediator, is(notNullValue()));
assertThat(mModel, is(notNullValue()));
}
@Test
@SmallTest
@Feature({"keyboard-accessory"})
public void testModelNotifiesAboutVisibilityOncePerChange() {
mModel.addObserver(mMockPropertyObserver);
// Calling show on the mediator should make model propagate that it's visible.
mMediator.show();
verify(mMockPropertyObserver)
.onPropertyChanged(mModel, AccessorySheetModel.PropertyKey.VISIBLE);
assertThat(mModel.isVisible(), is(true));
// Calling show again does nothing.
mMediator.show();
verify(mMockPropertyObserver) // Still the same call and no new one added.
.onPropertyChanged(mModel, AccessorySheetModel.PropertyKey.VISIBLE);
// Calling hide on the mediator should make model propagate that it's invisible.
mMediator.hide();
verify(mMockPropertyObserver, times(2))
.onPropertyChanged(mModel, AccessorySheetModel.PropertyKey.VISIBLE);
assertThat(mModel.isVisible(), is(false));
}
}
\ No newline at end of file
// Copyright 2018 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.autofill.keyboard_accessory;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
import android.view.ViewStub;
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.modelutil.ListObservable;
import org.chromium.ui.base.WindowAndroid;
/**
* Controller tests for the root controller for interactions with the manual filling UI.
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class ManualFillingControllerTest {
@Mock
private WindowAndroid mMockWindow;
@Mock
private ViewStub mMockViewStub;
@Mock
private KeyboardAccessoryView mMockView;
@Mock
private ListObservable.ListObserver mMockTabListObserver;
private KeyboardAccessoryCoordinator mKeyboardAccessory;
private ManualFillingController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mMockViewStub.inflate()).thenReturn(mMockView);
mKeyboardAccessory = new KeyboardAccessoryCoordinator(mMockWindow, mMockViewStub);
mController = new ManualFillingController(mKeyboardAccessory);
}
@Test
@SmallTest
public void testCreatesValidSubComponents() {
assertThat(mKeyboardAccessory, is(notNullValue()));
assertThat(mController, is(notNullValue()));
}
@Test
@SmallTest
public void testAddingBottomSheetsAddsTabsToAccessory() {
KeyboardAccessoryModel keyboardAccessoryModel =
mKeyboardAccessory.getMediatorForTesting().getModelForTesting();
keyboardAccessoryModel.addTabListObserver(mMockTabListObserver);
assertThat(keyboardAccessoryModel.getTabList().getItemCount(), is(0));
mController.addAccessorySheet(new AccessorySheetCoordinator(mMockViewStub));
verify(mMockTabListObserver).onItemRangeInserted(keyboardAccessoryModel.getTabList(), 0, 1);
assertThat(keyboardAccessoryModel.getTabList().getItemCount(), is(1));
}
}
\ No newline at end of file
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