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

[iOS][EG2] Create keyboard app interface

Create an app interface for the app code in fallback_coordinator_egtest
related to the keyboard.
Move the code from the test to this interface so it can be used later
to migrate the test to EG2.

Bug: 1017175
Change-Id: I08a85c003a1797d2ef5fa0cd8e4ec444dd05fb3f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1876392
Commit-Queue: Javier Ernesto Flores Robles <javierrobles@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#708952}
parent f2ac6241
...@@ -62,7 +62,7 @@ source_set("manual_fill") { ...@@ -62,7 +62,7 @@ source_set("manual_fill") {
"//ios/web/public", "//ios/web/public",
"//ios/web/public/deprecated", "//ios/web/public/deprecated",
"//ios/web/public/js_messaging", "//ios/web/public/js_messaging",
"//ui/base:base", "//ui/base",
] ]
libs = [ "UIKit.framework" ] libs = [ "UIKit.framework" ]
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
...@@ -183,7 +183,7 @@ source_set("requesters") { ...@@ -183,7 +183,7 @@ source_set("requesters") {
"//ios/chrome/browser/web_state_list:web_state_list", "//ios/chrome/browser/web_state_list:web_state_list",
"//ios/web/public:public", "//ios/web/public:public",
"//ios/web/public/js_messaging", "//ios/web/public/js_messaging",
"//ui/base:base", "//ui/base",
] ]
libs = [ "UIKit.framework" ] libs = [ "UIKit.framework" ]
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
......
...@@ -31,6 +31,8 @@ source_set("earl_grey_support") { ...@@ -31,6 +31,8 @@ source_set("earl_grey_support") {
"earl_grey_app.mm", "earl_grey_app.mm",
"earl_grey_test.h", "earl_grey_test.h",
"earl_grey_test.mm", "earl_grey_test.mm",
"keyboard_app_interface.h",
"keyboard_app_interface.mm",
"matchers.h", "matchers.h",
"matchers.mm", "matchers.mm",
] ]
...@@ -43,6 +45,7 @@ source_set("eg_app_support+eg2") { ...@@ -43,6 +45,7 @@ source_set("eg_app_support+eg2") {
deps = [ deps = [
"//base/test:test_support", "//base/test:test_support",
"//build/config/ios:xctest",
"//ios/third_party/earl_grey2:app_framework+link", "//ios/third_party/earl_grey2:app_framework+link",
"//testing/gtest:gtest", "//testing/gtest:gtest",
] ]
...@@ -54,6 +57,8 @@ source_set("eg_app_support+eg2") { ...@@ -54,6 +57,8 @@ source_set("eg_app_support+eg2") {
"coverage_utils.mm", "coverage_utils.mm",
"earl_grey_app.h", "earl_grey_app.h",
"earl_grey_app.mm", "earl_grey_app.mm",
"keyboard_app_interface.h",
"keyboard_app_interface.mm",
] ]
} }
...@@ -78,6 +83,7 @@ source_set("eg_test_support+eg2") { ...@@ -78,6 +83,7 @@ source_set("eg_test_support+eg2") {
"disabled_test_macros.h", "disabled_test_macros.h",
"earl_grey_test.h", "earl_grey_test.h",
"earl_grey_test.mm", "earl_grey_test.mm",
"keyboard_app_interface.h",
"matchers.h", "matchers.h",
"matchers.mm", "matchers.mm",
] ]
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#if defined(CHROME_EARL_GREY_1) #if defined(CHROME_EARL_GREY_1)
#import <EarlGrey/EarlGrey.h> #import <EarlGrey/EarlGrey.h>
#import <EarlGrey/GREYAppleInternals.h>
#import <EarlGrey/GREYKeyboard.h>
typedef DescribeToBlock GREYDescribeToBlock; typedef DescribeToBlock GREYDescribeToBlock;
typedef MatchesBlock GREYMatchesBlock; typedef MatchesBlock GREYMatchesBlock;
...@@ -30,6 +32,7 @@ void grey_dispatch_sync_on_main_thread(void (^block)(void)); ...@@ -30,6 +32,7 @@ void grey_dispatch_sync_on_main_thread(void (^block)(void));
#import <AppFramework/Matcher/GREYMatchersShorthand.h> #import <AppFramework/Matcher/GREYMatchersShorthand.h>
#import <AppFramework/Synchronization/GREYSyncAPI.h> #import <AppFramework/Synchronization/GREYSyncAPI.h>
#import <CommonLib/Error/GREYErrorConstants.h> #import <CommonLib/Error/GREYErrorConstants.h>
#import <CommonLib/GREYAppleInternals.h>
#else #else
#error Must define either CHROME_EARL_GREY_1 or CHROME_EARL_GREY_2. #error Must define either CHROME_EARL_GREY_1 or CHROME_EARL_GREY_2.
......
// Copyright 2019 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.
#ifndef IOS_TESTING_EARL_GREY_KEYBOARD_APP_INTERFACE_H_
#define IOS_TESTING_EARL_GREY_KEYBOARD_APP_INTERFACE_H_
#import <UIKit/UIKit.h>
@protocol GREYAction;
@protocol GREYMatcher;
// KeyboardAppInterface contains helpers for interacting with the keyboard.
// These are compiled into the app binary and can be called from either app or
// test code.
@interface KeyboardAppInterface : NSObject
// Return a boolean indicating if the keyboard is docked.
+ (BOOL)isKeyboadDocked;
// Matcher for the Keyboard Window.
+ (id<GREYMatcher>)keyboardWindowMatcher;
// Swipe action to undock the keyboard.
+ (id<GREYAction>)keyboardUndockAction;
// Swipe action to dock the keyboard.
+ (id<GREYAction>)keyboardDockAction;
// If the keyboard is not present this will add a text field to the hierarchy,
// make it first responder and return it. If it is already present, this does
// nothing and returns nil.
+ (UITextField*)showKeyboard;
@end
#endif // IOS_TESTING_EARL_GREY_KEYBOARD_APP_INTERFACE_H_
// Copyright 2019 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.
#import "ios/testing/earl_grey/keyboard_app_interface.h"
#import <UIKit/UIKit.h>
#include <atomic>
#import "base/test/ios/wait_util.h"
#import "ios/testing/earl_grey/earl_grey_app.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// EarlGrey fails to detect undocked keyboards on screen, so this help check
// for them.
static std::atomic_bool gCHRIsKeyboardShown(false);
// Returns the dismiss key if present in the passed keyboard layout. Returns nil
// if not found.
UIAccessibilityElement* KeyboardDismissKeyInLayout() {
UIView* layout = [[UIKeyboardImpl sharedInstance] _layout];
UIAccessibilityElement* key = nil;
if ([layout accessibilityElementCount] != NSNotFound) {
for (NSInteger i = [layout accessibilityElementCount]; i >= 0; --i) {
id element = [layout accessibilityElementAtIndex:i];
if ([[[element key] valueForKey:@"name"] isEqual:@"Dismiss-Key"]) {
key = element;
break;
}
}
}
return key;
}
// Returns YES if the keyboard is docked at the bottom. NO otherwise.
BOOL IsKeyboardDockedForLayout() {
UIView* layout = [[UIKeyboardImpl sharedInstance] _layout];
CGRect windowBounds = layout.window.bounds;
UIView* viewToCompare = layout;
while (viewToCompare &&
viewToCompare.bounds.size.height < windowBounds.size.height) {
CGRect keyboardFrameInWindow =
[viewToCompare.window convertRect:viewToCompare.bounds
fromView:viewToCompare];
CGFloat maxY = CGRectGetMaxY(keyboardFrameInWindow);
if ([@(maxY) isEqualToNumber:@(windowBounds.size.height)]) {
return YES;
}
viewToCompare = viewToCompare.superview;
}
return NO;
}
} // namespace
@implementation KeyboardAppInterface
+ (void)load {
@autoreleasepool {
// EarlGrey fails to detect undocked keyboards on screen, so this help check
// for them.
auto block = ^(NSNotification* note) {
CGRect keyboardFrame =
[note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
UIWindow* window = [UIApplication sharedApplication].keyWindow;
keyboardFrame = [window convertRect:keyboardFrame fromWindow:nil];
CGRect windowFrame = window.frame;
CGRect frameIntersection = CGRectIntersection(windowFrame, keyboardFrame);
gCHRIsKeyboardShown =
frameIntersection.size.width > 1 && frameIntersection.size.height > 1;
};
[[NSNotificationCenter defaultCenter]
addObserverForName:UIKeyboardDidChangeFrameNotification
object:nil
queue:nil
usingBlock:block];
[[NSNotificationCenter defaultCenter]
addObserverForName:UIKeyboardDidShowNotification
object:nil
queue:nil
usingBlock:block];
[[NSNotificationCenter defaultCenter]
addObserverForName:UIKeyboardDidHideNotification
object:nil
queue:nil
usingBlock:block];
}
}
+ (BOOL)isKeyboadDocked {
return IsKeyboardDockedForLayout();
}
+ (id<GREYMatcher>)keyboardWindowMatcher {
id<GREYMatcher> classMatcher = grey_kindOfClass([UIWindow class]);
UIAccessibilityElement* key = KeyboardDismissKeyInLayout();
id<GREYMatcher> parentMatcher =
grey_descendant(grey_accessibilityLabel(key.accessibilityLabel));
return grey_allOf(classMatcher, parentMatcher, nil);
}
+ (id<GREYAction>)keyboardUndockAction {
UIAccessibilityElement* key = KeyboardDismissKeyInLayout();
CGRect keyFrameInScreen = [key accessibilityFrame];
UIView* layout = [[UIKeyboardImpl sharedInstance] _layout];
CGRect keyFrameInWindow = [UIScreen.mainScreen.coordinateSpace
convertRect:keyFrameInScreen
toCoordinateSpace:layout.window.coordinateSpace];
CGRect windowBounds = layout.window.bounds;
CGPoint startPoint = CGPointMake(
(keyFrameInWindow.origin.x + keyFrameInWindow.size.width / 2.0) /
windowBounds.size.width,
(keyFrameInWindow.origin.y + keyFrameInWindow.size.height / 2.0) /
windowBounds.size.height);
return grey_swipeFastInDirectionWithStartPoint(kGREYDirectionUp, startPoint.x,
startPoint.y);
}
+ (id<GREYAction>)keyboardDockAction {
UIAccessibilityElement* key = KeyboardDismissKeyInLayout();
CGRect keyFrameInScreen = [key accessibilityFrame];
UIView* layout = [[UIKeyboardImpl sharedInstance] _layout];
CGRect keyFrameInWindow = [UIScreen.mainScreen.coordinateSpace
convertRect:keyFrameInScreen
toCoordinateSpace:layout.window.coordinateSpace];
CGRect windowBounds = layout.window.bounds;
CGPoint startPoint = CGPointMake(
(keyFrameInWindow.origin.x + keyFrameInWindow.size.width / 2.0) /
windowBounds.size.width,
(keyFrameInWindow.origin.y + keyFrameInWindow.size.height / 2.0) /
windowBounds.size.height);
return grey_swipeFastInDirectionWithStartPoint(kGREYDirectionDown,
startPoint.x, startPoint.y);
}
// If the keyboard is not present this will add a text field to the hierarchy,
// make it first responder and return it. If it is already present, this does
// nothing and returns nil.
+ (UITextField*)showKeyboard {
UITextField* textField = nil;
if (!gCHRIsKeyboardShown) {
CGRect rect = CGRectMake(0, 0, 300, 100);
textField = [[UITextField alloc] initWithFrame:rect];
textField.backgroundColor = [UIColor blueColor];
[[[UIApplication sharedApplication] keyWindow] addSubview:textField];
[textField becomeFirstResponder];
}
ConditionBlock conditionBlock = ^bool {
return gCHRIsKeyboardShown;
};
base::test::ios::TimeUntilCondition(
nil, conditionBlock, false,
base::TimeDelta::FromSeconds(base::test::ios::kWaitForUIElementTimeout));
return textField;
}
@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