Commit 145f5562 authored by Javier Ernesto Flores Robles's avatar Javier Ernesto Flores Robles Committed by Commit Bot

[iOS][MF] Present on iPad as popover

This CL enables presentation in iPads as a popover instead of above the keyboard.
This follows the UX design for Manual Fallback.
- Makes sure the accessory bar for iPad is always added when Manual Fallback is Enabled.
- The responsibility of not showing the accessory bar when other UI is presenting the
keyboard is now fully own by the input accessory bar view controller.

Bug: 845472
Cq-Include-Trybots: luci.chromium.try:ios-simulator-cronet;luci.chromium.try:ios-simulator-full-configs
Change-Id: Ife13cc44b4912084ccb10376ee9c53039dc00548
Reviewed-on: https://chromium-review.googlesource.com/c/1256793
Commit-Queue: Javier Ernesto Flores Robles <javierrobles@chromium.org>
Reviewed-by: default avatarMoe Ahmadi <mahmadi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600131}
parent ec6d5dcb
......@@ -124,19 +124,20 @@ CGFloat const kInputAccessoryHeight = 44.0f;
return;
}
// If this is a form suggestion view and no suggestions have been triggered
// yet, don't show the custom view.
FormSuggestionView* formSuggestionView =
base::mac::ObjCCast<FormSuggestionView>(view);
if (formSuggestionView) {
int numSuggestions = [[formSuggestionView suggestions] count];
if (!_suggestionsHaveBeenShown && numSuggestions == 0) {
self.customAccessoryView = nil;
return;
if (!autofill::features::IsPasswordManualFallbackEnabled()) {
// If this is a form suggestion view and no suggestions have been
// triggered yet, don't show the custom view.
FormSuggestionView* formSuggestionView =
base::mac::ObjCCast<FormSuggestionView>(view);
if (formSuggestionView) {
int numSuggestions = [[formSuggestionView suggestions] count];
if (!_suggestionsHaveBeenShown && numSuggestions == 0) {
self.customAccessoryView = nil;
return;
}
}
_suggestionsHaveBeenShown = YES;
}
_suggestionsHaveBeenShown = YES;
self.customAccessoryView = [[FormInputAccessoryView alloc] init];
[self.customAccessoryView setUpWithCustomView:view];
[self addCustomAccessoryViewIfNeeded];
......@@ -249,7 +250,6 @@ CGFloat const kInputAccessoryHeight = 44.0f;
// keyboard view is created by the system, i.e. the first time the keyboard
// will appear.
if (!IsIPadIdiom()) {
[self addCustomAccessoryViewIfNeeded];
[self addCustomKeyboardViewIfNeeded];
}
}
......
......@@ -24,7 +24,7 @@ class WebStateList;
// accessory view elements.
@interface FormInputAccessoryCoordinator : ChromeCoordinator
// The delegate for the password coordinator. Must be set before it starts.
// The delegate for the coordinator. Must be set before it starts.
@property(nonatomic, weak) id<FormInputAccessoryCoordinatorDelegate> delegate;
// Creates a coordinator that uses a |viewController| a |browserState| and
......
......@@ -11,6 +11,7 @@
#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h"
#include "ios/chrome/browser/ui/ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -97,7 +98,7 @@
[self.childCoordinators removeAllObjects];
}
- (void)startPasswords {
- (void)startPasswordsFromButton:(UIButton*)button {
ManualFillPasswordCoordinator* passwordCoordinator =
[[ManualFillPasswordCoordinator alloc]
initWithBaseViewController:self.baseViewController
......@@ -105,10 +106,14 @@
webStateList:self.webStateList
injectionHandler:self.manualFillInjectionHandler];
passwordCoordinator.delegate = self;
[self.formInputAccessoryViewController
presentView:passwordCoordinator.viewController.view];
[self.childCoordinators addObject:passwordCoordinator];
if (IsIPadIdiom()) {
[passwordCoordinator presentFromButton:button];
} else {
[self.formInputAccessoryViewController
presentView:passwordCoordinator.viewController.view];
}
[self.childCoordinators addObject:passwordCoordinator];
[self.formInputAccessoryMediator disableSuggestions];
}
......@@ -129,9 +134,9 @@
// TODO(crbug.com/845472): implement.
}
- (void)passwordButtonPressed {
- (void)passwordButtonPressed:(UIButton*)sender {
[self stopChildren];
[self startPasswords];
[self startPasswordsFromButton:sender];
}
#pragma mark - PasswordCoordinatorDelegate
......@@ -140,4 +145,8 @@
[self.delegate openPasswordSettings];
}
- (void)resetAccessoryView {
[self.manualFillAccessoryViewController reset];
}
@end
......@@ -131,6 +131,14 @@
selector:@selector(handleTextInputDidBeginEditing:)
name:UITextFieldTextDidBeginEditingNotification
object:nil];
[defaultCenter addObserver:self
selector:@selector(handleTextInputDidEndEditing:)
name:UITextFieldTextDidEndEditingNotification
object:nil];
[defaultCenter addObserver:self
selector:@selector(handleKeyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
_keyboardObserver = [[KeyboardObserverHelper alloc] init];
_keyboardObserver.delegate = self;
}
......@@ -416,13 +424,29 @@ queryViewBlockForProvider:(id<FormInputAccessoryViewProvider>)provider
navigationDelegate:self.formInputAccessoryHandler];
}
// When any text field or text view (e.g. omnibox, settings, card unmask dialog)
// begins editing, reset ourselves so that we don't present our custom view over
#pragma mark - Keyboard Notifications
// When the keyboard is shown, send the last suggestions to the consumer.
- (void)handleKeyboardWillShow:(NSNotification*)notification {
if (self.lastSuggestionView) {
[self updateWithProvider:self.lastProvider
suggestionView:self.lastSuggestionView];
}
}
// When any text field or text view (e.g. omnibox, settings search bar)
// begins editing, pause the consumer so it doesn't present the custom view over
// the keyboard.
- (void)handleTextInputDidBeginEditing:(NSNotification*)notification {
[self.consumer pauseCustomKeyboardView];
}
// When any text field or text view (e.g. omnibox, settings, card unmask dialog)
// ends editing, continue presenting.
- (void)handleTextInputDidEndEditing:(NSNotification*)notification {
[self.consumer continueCustomKeyboardView];
}
#pragma mark - Tests
- (void)injectWebState:(web::WebState*)webState {
......
......@@ -28,9 +28,11 @@ source_set("manual_fill") {
"//ios/chrome/browser/autofill:autofill_shared",
"//ios/chrome/browser/autofill/manual_fill:manual_fill",
"//ios/chrome/browser/passwords",
"//ios/chrome/browser/ui:ui_util",
"//ios/chrome/browser/ui/autofill/manual_fill:manual_fill_ui",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators",
"//ios/chrome/browser/ui/list_model:list_model",
"//ios/chrome/browser/ui/table_view:presentation",
"//ios/chrome/browser/ui/table_view:table_view",
"//ios/chrome/browser/web_state_list:web_state_list",
"//ios/web/public:public",
......
......@@ -33,7 +33,7 @@ extern NSString* const AccessoryCreditCardAccessibilityIdentifier;
- (void)keyboardButtonPressed;
// Invoked after the user touches the `passwords` button.
- (void)passwordButtonPressed;
- (void)passwordButtonPressed:(UIButton*)sender;
@end
......
......@@ -6,6 +6,7 @@
#include "components/autofill/core/common/autofill_features.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/uicolor_manualfill.h"
#include "ios/chrome/browser/ui/ui_util.h"
#import "ios/chrome/common/ui_util/constraints_ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
......@@ -62,17 +63,21 @@ static NSTimeInterval MFAnimationDuration = 0.20;
self.view.translatesAutoresizingMaskIntoConstraints = NO;
UIColor* tintColor = [self activeTintColor];
self.keyboardButton = [UIButton buttonWithType:UIButtonTypeSystem];
UIImage* keyboardImage = [UIImage imageNamed:@"ic_keyboard"];
[self.keyboardButton setImage:keyboardImage forState:UIControlStateNormal];
self.keyboardButton.tintColor = tintColor;
self.keyboardButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.keyboardButton addTarget:self
action:@selector(keyboardButtonPressed)
forControlEvents:UIControlEventTouchUpInside];
self.keyboardButton.accessibilityIdentifier =
manual_fill::AccessoryKeyboardAccessibilityIdentifier;
NSMutableArray<UIView*>* icons = [[NSMutableArray alloc] init];
if (!IsIPadIdiom()) {
self.keyboardButton = [UIButton buttonWithType:UIButtonTypeSystem];
UIImage* keyboardImage = [UIImage imageNamed:@"ic_keyboard"];
[self.keyboardButton setImage:keyboardImage forState:UIControlStateNormal];
self.keyboardButton.tintColor = tintColor;
self.keyboardButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.keyboardButton addTarget:self
action:@selector(keyboardButtonPressed)
forControlEvents:UIControlEventTouchUpInside];
self.keyboardButton.accessibilityIdentifier =
manual_fill::AccessoryKeyboardAccessibilityIdentifier;
[icons addObject:self.keyboardButton];
}
self.passwordButton = [UIButton buttonWithType:UIButtonTypeSystem];
UIImage* keyImage = [UIImage imageNamed:@"ic_vpn_key"];
......@@ -80,12 +85,12 @@ static NSTimeInterval MFAnimationDuration = 0.20;
self.passwordButton.tintColor = tintColor;
self.passwordButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.passwordButton addTarget:self
action:@selector(passwordButtonPressed)
action:@selector(passwordButtonPressed:)
forControlEvents:UIControlEventTouchUpInside];
self.passwordButton.accessibilityIdentifier =
manual_fill::AccessoryPasswordAccessibilityIdentifier;
[icons addObject:self.passwordButton];
NSArray* views;
if (autofill::features::IsAutofillManualFallbackEnabled()) {
self.cardsButton = [UIButton buttonWithType:UIButtonTypeSystem];
UIImage* cardImage = [UIImage imageNamed:@"ic_credit_card"];
......@@ -97,6 +102,7 @@ static NSTimeInterval MFAnimationDuration = 0.20;
forControlEvents:UIControlEventTouchUpInside];
self.cardsButton.accessibilityIdentifier =
manual_fill::AccessoryCreditCardAccessibilityIdentifier;
[icons addObject:self.cardsButton];
self.accountButton = [UIButton buttonWithType:UIButtonTypeSystem];
UIImage* accountImage = [UIImage imageNamed:@"addresses"];
......@@ -108,15 +114,9 @@ static NSTimeInterval MFAnimationDuration = 0.20;
forControlEvents:UIControlEventTouchUpInside];
self.accountButton.accessibilityIdentifier =
manual_fill::AccessoryAddressAccessibilityIdentifier;
views = @[
self.keyboardButton, self.passwordButton, self.accountButton,
self.cardsButton
];
} else {
views = @[ self.keyboardButton, self.passwordButton ];
[icons addObject:self.accountButton];
}
UIStackView* stackView = [[UIStackView alloc] initWithArrangedSubviews:views];
UIStackView* stackView = [[UIStackView alloc] initWithArrangedSubviews:icons];
stackView.spacing = 10;
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.translatesAutoresizingMaskIntoConstraints = NO;
......@@ -177,11 +177,11 @@ static NSTimeInterval MFAnimationDuration = 0.20;
[self.delegate keyboardButtonPressed];
}
- (void)passwordButtonPressed {
- (void)passwordButtonPressed:(UIButton*)sender {
[self animateKeyboardButtonHidden:NO];
[self resetTintColors];
[self.passwordButton setTintColor:UIColor.cr_manualFillTintColor];
[self.delegate passwordButtonPressed];
[self.delegate passwordButtonPressed:sender];
}
- (void)cardButtonPressed {
......
......@@ -10,9 +10,18 @@
@class ManualFillInjectionHandler;
class WebStateList;
namespace manual_fill {
extern NSString* const PasswordDoneButtonAccessibilityIdentifier;
} // namespace manual_fill
// Delegate for the coordinator actions.
@protocol PasswordCoordinatorDelegate<NSObject>
// Resets the accessory view.
- (void)resetAccessoryView;
// Opens the passwords settings.
- (void)openPasswordSettings;
......@@ -43,6 +52,9 @@ initWithBaseViewController:(UIViewController*)viewController
(ios::ChromeBrowserState*)browserState
NS_UNAVAILABLE;
// Presents the password view controller as a popover from the passed button.
- (void)presentFromButton:(UIButton*)button;
@end
#endif // IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_PASSWORD_COORDINATOR_H_
......@@ -11,12 +11,26 @@
#import "ios/chrome/browser/ui/autofill/manual_fill/password_list_delegate.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/password_mediator.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.h"
#import "ios/chrome/browser/ui/table_view/table_view_animator.h"
#import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
#import "ios/chrome/browser/ui/table_view/table_view_presentation_controller.h"
#include "ios/chrome/browser/ui/ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface ManualFillPasswordCoordinator ()<PasswordListDelegate>
namespace manual_fill {
NSString* const PasswordDoneButtonAccessibilityIdentifier =
@"kManualFillPasswordDoneButtonAccessibilityIdentifier";
} // namespace manual_fill
@interface ManualFillPasswordCoordinator ()<
PasswordListDelegate,
UIViewControllerTransitioningDelegate,
UIPopoverPresentationControllerDelegate>
// Fetches and filters the passwords for the view controller.
@property(nonatomic, strong) ManualFillPasswordMediator* passwordMediator;
......@@ -34,6 +48,10 @@
@property(nonatomic, strong)
ManualFillInjectionHandler* manualFillInjectionHandler;
// Button presenting this coordinator in a popover. Used for continuation after
// dismissing any presented view controller. iPad only.
@property(nonatomic, weak) UIButton* presentingButton;
@end
@implementation ManualFillPasswordCoordinator
......@@ -69,7 +87,12 @@ initWithBaseViewController:(UIViewController*)viewController
}
- (void)stop {
[self.passwordViewController.view removeFromSuperview];
if (IsIPadIdiom() && self.passwordViewController.presentingViewController) {
[self.passwordViewController dismissViewControllerAnimated:true
completion:nil];
} else {
[self.passwordViewController.view removeFromSuperview];
}
[self.allPasswordsViewController dismissViewControllerAnimated:YES
completion:nil];
}
......@@ -78,9 +101,83 @@ initWithBaseViewController:(UIViewController*)viewController
return self.passwordViewController;
}
- (void)presentFromButton:(UIButton*)button {
self.presentingButton = button;
self.passwordViewController.modalPresentationStyle =
UIModalPresentationPopover;
[self.baseViewController presentViewController:self.passwordViewController
animated:YES
completion:nil];
UIPopoverPresentationController* popoverPresentationController =
self.passwordViewController.popoverPresentationController;
popoverPresentationController.sourceView = button;
popoverPresentationController.sourceRect = button.bounds;
popoverPresentationController.permittedArrowDirections =
UIPopoverArrowDirectionUp | UIMenuControllerArrowDown;
popoverPresentationController.delegate = self;
}
#pragma mark - UIViewControllerTransitioningDelegate
- (UIPresentationController*)
presentationControllerForPresentedViewController:(UIViewController*)presented
presentingViewController:(UIViewController*)presenting
sourceViewController:(UIViewController*)source {
TableViewPresentationController* presentationController =
[[TableViewPresentationController alloc]
initWithPresentedViewController:presented
presentingViewController:presenting];
presentationController.position = TablePresentationPositionLeading;
return presentationController;
}
- (id<UIViewControllerAnimatedTransitioning>)
animationControllerForPresentedController:(UIViewController*)presented
presentingController:(UIViewController*)presenting
sourceController:(UIViewController*)source {
UITraitCollection* traitCollection = presenting.traitCollection;
if (traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact &&
traitCollection.verticalSizeClass != UIUserInterfaceSizeClassCompact) {
// Use the default animator for fullscreen presentations.
return nil;
}
TableViewAnimator* animator = [[TableViewAnimator alloc] init];
animator.presenting = YES;
animator.direction = TableAnimatorDirectionFromLeading;
return animator;
}
- (id<UIViewControllerAnimatedTransitioning>)
animationControllerForDismissedController:(UIViewController*)dismissed {
UITraitCollection* traitCollection = dismissed.traitCollection;
if (traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact &&
traitCollection.verticalSizeClass != UIUserInterfaceSizeClassCompact) {
// Use the default animator for fullscreen presentations.
return nil;
}
TableViewAnimator* animator = [[TableViewAnimator alloc] init];
animator.presenting = NO;
animator.direction = TableAnimatorDirectionFromLeading;
return animator;
}
#pragma mark - PasswordListDelegate
- (void)openAllPasswordsList {
// On iPad, first dismiss the popover before the new view is presented.
__weak __typeof(self) weakSelf = self;
if (IsIPadIdiom() && self.passwordViewController.presentingViewController) {
[self.passwordViewController
dismissViewControllerAnimated:true
completion:^{
[weakSelf openAllPasswordsList];
}];
return;
}
UISearchController* searchController =
[[UISearchController alloc] initWithSearchResultsController:nil];
searchController.searchResultsUpdater = self.passwordMediator;
......@@ -89,26 +186,57 @@ initWithBaseViewController:(UIViewController*)viewController
[PasswordViewController alloc] initWithSearchController:searchController];
self.passwordMediator.disableFilter = YES;
self.passwordMediator.consumer = allPasswordsViewController;
UINavigationController* navigationController = [[UINavigationController alloc]
initWithRootViewController:allPasswordsViewController];
if (@available(iOS 11, *)) {
navigationController.navigationBar.prefersLargeTitles = YES;
}
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(dismissPresentedViewController)];
doneButton.accessibilityIdentifier =
manual_fill::PasswordDoneButtonAccessibilityIdentifier;
allPasswordsViewController.navigationItem.rightBarButtonItem = doneButton;
self.allPasswordsViewController = allPasswordsViewController;
TableViewNavigationController* navigationController =
[[TableViewNavigationController alloc]
initWithTable:allPasswordsViewController];
navigationController.transitioningDelegate = self;
[navigationController setModalPresentationStyle:UIModalPresentationCustom];
[self.baseViewController presentViewController:navigationController
animated:YES
completion:nil];
}
- (void)dismissPresentedViewController {
// Dismiss the full screen view controller and present the pop over.
__weak __typeof(self) weakSelf = self;
[self.allPasswordsViewController.presentingViewController
dismissViewControllerAnimated:YES
completion:nil];
completion:^{
if (weakSelf.presentingButton) {
[weakSelf
presentFromButton:weakSelf.presentingButton];
}
}];
}
- (void)openPasswordSettings {
// On iPad, dismiss the popover before the settings are presented.
if (IsIPadIdiom() && self.passwordViewController.presentingViewController) {
[self.passwordViewController
dismissViewControllerAnimated:true
completion:^{
[self openPasswordSettings];
}];
return;
}
[self.delegate openPasswordSettings];
}
#pragma mark - UIPopoverPresentationControllerDelegate
- (void)popoverPresentationControllerDidDismissPopover:
(UIPopoverPresentationController*)popoverPresentationController {
[self.delegate resetAccessoryView];
}
@end
......@@ -7,12 +7,17 @@
// Delegate for actions in manual fallback's passwords list.
@protocol PasswordListDelegate
// Dismisses the presented view controller.
// Dismisses the presented view controller and continues as pop over on iPads
// or above the keyboard else.
- (void)dismissPresentedViewController;
// Requests to open the list of all passwords.
- (void)openAllPasswordsList;
// Opens passwords settings.
- (void)openPasswordSettings;
@end
#endif // IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_PASSWORD_LIST_DELEGATE_H_
......@@ -8,6 +8,7 @@
#import "ios/chrome/browser/ui/autofill/manual_fill/action_cell.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_cell.h"
#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
#include "ios/chrome/browser/ui/ui_util.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util_mac.h"
......@@ -31,6 +32,12 @@ typedef NS_ENUM(NSInteger, SectionIdentifier) {
ActionsSectionIdentifier,
};
// This is the width used for |self.preferredContentSize|.
constexpr float PopoverPreferredWidth = 320;
// This is the maximum height used for |self.preferredContentSize|.
constexpr float PopoverMaxHeight = 250;
} // namespace
@interface PasswordViewController ()
......@@ -80,10 +87,6 @@ typedef NS_ENUM(NSInteger, SectionIdentifier) {
NSString* titleString =
l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD);
self.title = titleString;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(handleDoneNavigationItemTap)];
if (!base::ios::IsRunningOnIOS11OrLater()) {
// On iOS 11 this is not needed since the cell constrains are updated by the
......@@ -108,11 +111,6 @@ typedef NS_ENUM(NSInteger, SectionIdentifier) {
#pragma mark - Private
// Callback for the "Done" navigation item.
- (void)handleDoneNavigationItemTap {
[self dismissViewControllerAnimated:YES completion:nil];
}
// Presents |items| in the respective section. Handles creating or deleting the
// section accordingly.
- (void)presentItems:(NSArray<TableViewItem*>*)items
......@@ -145,6 +143,15 @@ typedef NS_ENUM(NSInteger, SectionIdentifier) {
}
}
[self.tableView reloadData];
if (IsIPadIdiom()) {
// Update the preffered content size on iPad so the popover shows the right
// size.
[self.tableView layoutIfNeeded];
CGSize systemLayoutSize = self.tableView.contentSize;
CGFloat preferredHeight = MIN(systemLayoutSize.height, PopoverMaxHeight);
self.preferredContentSize =
CGSizeMake(PopoverPreferredWidth, preferredHeight);
}
}
@end
......@@ -16,6 +16,7 @@
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/password_mediator.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.h"
#import "ios/chrome/browser/ui/ui_util.h"
......@@ -48,6 +49,11 @@ id<GREYMatcher> PasswordIconMatcher() {
manual_fill::AccessoryPasswordAccessibilityIdentifier);
}
id<GREYMatcher> KeyboardIconMatcher() {
return grey_accessibilityID(
manual_fill::AccessoryKeyboardAccessibilityIdentifier);
}
// Returns a matcher for the password table view in manual fallback.
id<GREYMatcher> PasswordTableViewMatcher() {
return grey_accessibilityID(
......@@ -73,6 +79,11 @@ id<GREYMatcher> OtherPasswordsMatcher() {
manual_fill::OtherPasswordsAccessibilityIdentifier);
}
id<GREYMatcher> OtherPasswordsDismissMatcher() {
return grey_accessibilityID(
manual_fill::PasswordDoneButtonAccessibilityIdentifier);
}
// Returns a matcher for the example username in the list.
id<GREYMatcher> UsernameButtonMatcher() {
return grey_buttonTitle(base::SysUTF8ToNSString(kExampleUsername));
......@@ -208,12 +219,8 @@ void ClearPasswordStore() {
[super tearDown];
}
// Test that the passwords view controller appears on screen.
// Tests that the passwords view controller appears on screen.
- (void)testPasswordsViewControllerIsPresented {
// TODO:(https://crbug.com/878388) Enable on iPad when supported.
if (IsIPadIdiom())
return;
// Bring up the keyboard.
[[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
performAction:chrome_test_util::TapWebElement(kFormElementUsername)];
......@@ -227,13 +234,9 @@ void ClearPasswordStore() {
assertWithMatcher:grey_sufficientlyVisible()];
}
// Test that the passwords view controller contains the "Manage Passwords..."
// Tests that the passwords view controller contains the "Manage Passwords..."
// action.
- (void)testPasswordsViewControllerContainsManagePasswordsAction {
// TODO:(https://crbug.com/878388) Enable on iPad when supported.
if (IsIPadIdiom())
return;
// Bring up the keyboard.
[[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
performAction:chrome_test_util::TapWebElement(kFormElementUsername)];
......@@ -247,12 +250,8 @@ void ClearPasswordStore() {
assertWithMatcher:grey_interactable()];
}
// Test that the "Manage Passwords..." action works.
// Tests that the "Manage Passwords..." action works.
- (void)testManagePasswordsActionOpensPasswordSettings {
// TODO:(https://crbug.com/878388) Enable on iPad when supported.
if (IsIPadIdiom())
return;
// Bring up the keyboard.
[[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
performAction:chrome_test_util::TapWebElement(kFormElementUsername)];
......@@ -270,12 +269,8 @@ void ClearPasswordStore() {
assertWithMatcher:grey_sufficientlyVisible()];
}
// Test that the Password View Controller is not present when presenting UI.
// Tests that the Password View Controller is not present when presenting UI.
- (void)testPasswordControllerPauses {
// TODO:(https://crbug.com/878388) Enable on iPad when supported.
if (IsIPadIdiom())
return;
// For the search bar to appear in password settings at least one password is
// needed.
SaveExamplePasswordForm();
......@@ -293,7 +288,6 @@ void ClearPasswordStore() {
performAction:grey_tap()];
// Tap the password search.
[[EarlGrey selectElementWithMatcher:PasswordSettingsSearchMatcher()]
performAction:grey_tap()];
......@@ -303,13 +297,9 @@ void ClearPasswordStore() {
assertWithMatcher:grey_notVisible()];
}
// Test that the Password View Controller is resumed after selecting other
// Tests that the Password View Controller is resumed after selecting other
// password.
- (void)testPasswordControllerResumes {
// TODO:(https://crbug.com/878388) Enable on iPad when supported.
if (IsIPadIdiom())
return;
// For this test one password is needed.
SaveExamplePasswordForm();
......@@ -321,7 +311,7 @@ void ClearPasswordStore() {
[[EarlGrey selectElementWithMatcher:PasswordIconMatcher()]
performAction:grey_tap()];
// Tap the "Manage Passwords..." action.
// Tap the "Other Passwords..." action.
[[EarlGrey selectElementWithMatcher:OtherPasswordsMatcher()]
performAction:grey_tap()];
......@@ -334,18 +324,113 @@ void ClearPasswordStore() {
[[EarlGrey selectElementWithMatcher:UsernameButtonMatcher()]
performAction:grey_tap()];
// Only on iOS 12 it is certain that on iPhones the keyboard is back. On iOS
// 11, it varies by device and version.
if (base::ios::IsRunningOnIOS12OrLater()) {
// Verify the password controller table view and the keyboard are visible.
GREYAssertTrue([GREYKeyboard isKeyboardShown], @"Keyboard Should be Shown");
// Wait for the password list to disappear. Using the search bar, since the
// popover doesn't have it.
[[EarlGrey selectElementWithMatcher:PasswordSearchBarMatcher()]
assertWithMatcher:grey_notVisible()];
// Only on iOS 11.3 it is certain that on iPhones the keyboard is back. On iOS
// 11.0-11.2, it varies by device and version.
if ([GREYKeyboard isKeyboardShown]) {
[[EarlGrey selectElementWithMatcher:PasswordTableViewMatcher()]
assertWithMatcher:grey_sufficientlyVisible()];
[[EarlGrey selectElementWithMatcher:PasswordIconMatcher()]
assertWithMatcher:grey_sufficientlyVisible()];
}
}
// Tests that the Password View Controller is resumed after dismissing "Other
// Passwords".
- (void)testPasswordControllerResumesWhenOtherPasswordsDismiss {
// Bring up the keyboard.
[[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
performAction:chrome_test_util::TapWebElement(kFormElementUsername)];
// Tap on the passwords icon.
[[EarlGrey selectElementWithMatcher:PasswordIconMatcher()]
performAction:grey_tap()];
// Tap the "Other Passwords..." action.
[[EarlGrey selectElementWithMatcher:OtherPasswordsMatcher()]
performAction:grey_tap()];
// Dismiss the Other Passwords view.
[[EarlGrey selectElementWithMatcher:OtherPasswordsDismissMatcher()]
performAction:grey_tap()];
// Wait for the password list to disappear. Using the search bar, since the
// popover doesn't have it.
[[EarlGrey selectElementWithMatcher:PasswordSearchBarMatcher()]
assertWithMatcher:grey_notVisible()];
// Only on iOS 11.3 it is certain that on iPhones the keyboard is back. On iOS
// 11.0-11.2, it varies by device and version.
if ([GREYKeyboard isKeyboardShown]) {
[[EarlGrey selectElementWithMatcher:PasswordTableViewMatcher()]
assertWithMatcher:grey_sufficientlyVisible()];
} else if (!base::ios::IsRunningOnIOS11OrLater()) {
// On iOS 10 the keyboard is hidden.
GREYAssertFalse([GREYKeyboard isKeyboardShown],
@"Keyboard Should be Hidden");
[[EarlGrey selectElementWithMatcher:PasswordIconMatcher()]
assertWithMatcher:grey_sufficientlyVisible()];
}
}
// Tests that the Password View Controller is dismissed when tapping the
// keyboard icon.
- (void)testKeyboardIconDismissPasswordController {
if (IsIPadIdiom()) {
// The keyboard icon is never present in iPads.
return;
}
// Bring up the keyboard.
[[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
performAction:chrome_test_util::TapWebElement(kFormElementUsername)];
// Tap on the passwords icon.
[[EarlGrey selectElementWithMatcher:PasswordIconMatcher()]
performAction:grey_tap()];
// Verify the password controller table view is visible.
[[EarlGrey selectElementWithMatcher:PasswordTableViewMatcher()]
assertWithMatcher:grey_sufficientlyVisible()];
// Tap on the keyboard icon.
[[EarlGrey selectElementWithMatcher:KeyboardIconMatcher()]
performAction:grey_tap()];
// Verify the password controller table view and the password icon is NOT
// visible.
[[EarlGrey selectElementWithMatcher:PasswordTableViewMatcher()]
assertWithMatcher:grey_notVisible()];
[[EarlGrey selectElementWithMatcher:KeyboardIconMatcher()]
assertWithMatcher:grey_notVisible()];
}
// Tests that the Password View Controller is dismissed when tapping the outside
// the popover on iPad.
- (void)testIPadTappingOutsidePopOverDismissPasswordController {
if (!IsIPadIdiom()) {
return;
}
// Bring up the keyboard.
[[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
performAction:chrome_test_util::TapWebElement(kFormElementUsername)];
// Tap on the passwords icon.
[[EarlGrey selectElementWithMatcher:PasswordIconMatcher()]
performAction:grey_tap()];
// Verify the password controller table view is visible.
[[EarlGrey selectElementWithMatcher:PasswordTableViewMatcher()]
assertWithMatcher:grey_sufficientlyVisible()];
// Tap on a point outside of the popover.
[[EarlGrey selectElementWithMatcher:grey_keyWindow()]
performAction:grey_tapAtPoint(CGPointMake(0, 0))];
// Verify the password controller table view and the password icon is NOT
// visible.
[[EarlGrey selectElementWithMatcher:PasswordTableViewMatcher()]
assertWithMatcher:grey_notVisible()];
[[EarlGrey selectElementWithMatcher:KeyboardIconMatcher()]
assertWithMatcher:grey_notVisible()];
}
@end
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