[iOS] Add SPI to customize the input accessory view when focusing an element
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Oct 2018 20:59:19 +0000 (20:59 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Oct 2018 20:59:19 +0000 (20:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190152
<rdar://problem/42754975>

Reviewed by Dan Bernstein.

Source/WebKit:

Adds SPI on WKFormInputSession to customize the input accessory view, alongside the input view. See below for
more details.

Test: KeyboardInputTests.CustomInputViewAndInputAccessoryView

* UIProcess/API/Cocoa/_WKFormInputSession.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKFormInputSession customInputAccessoryView]):
(-[WKFormInputSession setCustomInputAccessoryView:]):

Reload input views when the custom input accessory view changes.

(-[WKContentView requiresAccessoryView]):

If a custom input accessory view is specified, return YES.

(-[WKContentView inputAccessoryView]):

Return the custom input accessory view if present, and fall back to the default web form accessory view.

Tools:

Add an API test to verify that setting a custom input accessory view and custom input view on the form input
session when focusing an element overrides the first responder's (i.e. WKContentView's) `-inputView` and
`-inputAccessoryView`.

* TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm:
(webViewWithAutofocusedInput):
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/ios/TestInputDelegate.h:
* TestWebKitAPI/Tests/ios/TestInputDelegate.mm:
(-[TestInputDelegate setWillStartInputSessionHandler:]):
(-[TestInputDelegate willStartInputSessionHandler]):
(-[TestInputDelegate _webView:willStartInputSession:]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236691 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/Cocoa/_WKFormInputSession.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm
Tools/TestWebKitAPI/Tests/ios/TestInputDelegate.h
Tools/TestWebKitAPI/Tests/ios/TestInputDelegate.mm

index c832406..8519189 100644 (file)
@@ -1,3 +1,31 @@
+2018-10-01  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Add SPI to customize the input accessory view when focusing an element
+        https://bugs.webkit.org/show_bug.cgi?id=190152
+        <rdar://problem/42754975>
+
+        Reviewed by Dan Bernstein.
+
+        Adds SPI on WKFormInputSession to customize the input accessory view, alongside the input view. See below for
+        more details.
+
+        Test: KeyboardInputTests.CustomInputViewAndInputAccessoryView
+
+        * UIProcess/API/Cocoa/_WKFormInputSession.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKFormInputSession customInputAccessoryView]):
+        (-[WKFormInputSession setCustomInputAccessoryView:]):
+
+        Reload input views when the custom input accessory view changes.
+
+        (-[WKContentView requiresAccessoryView]):
+
+        If a custom input accessory view is specified, return YES.
+
+        (-[WKContentView inputAccessoryView]):
+
+        Return the custom input accessory view if present, and fall back to the default web form accessory view.
+
 2018-10-01  Sihui Liu  <sihui_liu@apple.com>
 
         Remove StorageProcess
index ed39c39..93547fc 100644 (file)
@@ -41,6 +41,7 @@
 #if TARGET_OS_IPHONE
 @property (nonatomic, copy) NSString *accessoryViewCustomButtonTitle;
 @property (nonatomic, strong) UIView *customInputView WK_API_AVAILABLE(ios(10.0));
+@property (nonatomic, strong) UIView *customInputAccessoryView WK_API_AVAILABLE(ios(WK_IOS_TBA));
 @property (nonatomic, copy) NSArray<UITextSuggestion *> *suggestions WK_API_AVAILABLE(ios(10.0));
 @property (nonatomic) BOOL accessoryViewShouldNotShow WK_API_AVAILABLE(ios(10.0));
 @property (nonatomic) BOOL forceSecureTextEntry WK_API_AVAILABLE(ios(10.0));
index a4b60b6..b01c4f6 100644 (file)
@@ -293,6 +293,7 @@ const CGFloat minimumTapHighlightRadius = 2.0;
     WeakObjCPtr<WKContentView> _contentView;
     RetainPtr<WKFocusedElementInfo> _focusedElementInfo;
     RetainPtr<UIView> _customInputView;
+    RetainPtr<UIView> _customInputAccessoryView;
     RetainPtr<NSArray<UITextSuggestion *>> _suggestions;
     BOOL _accessoryViewShouldNotShow;
     BOOL _forceSecureTextEntry;
@@ -383,6 +384,20 @@ const CGFloat minimumTapHighlightRadius = 2.0;
     [_contentView reloadInputViews];
 }
 
+- (UIView *)customInputAccessoryView
+{
+    return _customInputAccessoryView.get();
+}
+
+- (void)setCustomInputAccessoryView:(UIView *)customInputAccessoryView
+{
+    if (_customInputAccessoryView == customInputAccessoryView)
+        return;
+
+    _customInputAccessoryView = customInputAccessoryView;
+    [_contentView reloadInputViews];
+}
+
 - (void)endEditing
 {
     if ([_customInputView conformsToProtocol:@protocol(WKFormControl)])
@@ -2089,6 +2104,9 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     if ([_formInputSession accessoryViewShouldNotShow])
         return NO;
 
+    if ([_formInputSession customInputAccessoryView])
+        return YES;
+
     if (_assistedNodeInformation.inputMode == InputMode::None)
         return NO;
 
@@ -2133,7 +2151,7 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     if (![self requiresAccessoryView])
         return nil;
 
-    return self.formAccessoryView;
+    return [_formInputSession customInputAccessoryView] ?: self.formAccessoryView;
 }
 
 - (NSArray *)supportedPasteboardTypesForCurrentSelection
index a1678b3..a324975 100644 (file)
@@ -1,3 +1,24 @@
+2018-10-01  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Add SPI to customize the input accessory view when focusing an element
+        https://bugs.webkit.org/show_bug.cgi?id=190152
+        <rdar://problem/42754975>
+
+        Reviewed by Dan Bernstein.
+
+        Add an API test to verify that setting a custom input accessory view and custom input view on the form input
+        session when focusing an element overrides the first responder's (i.e. WKContentView's) `-inputView` and
+        `-inputAccessoryView`.
+
+        * TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm:
+        (webViewWithAutofocusedInput):
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/ios/TestInputDelegate.h:
+        * TestWebKitAPI/Tests/ios/TestInputDelegate.mm:
+        (-[TestInputDelegate setWillStartInputSessionHandler:]):
+        (-[TestInputDelegate willStartInputSessionHandler]):
+        (-[TestInputDelegate _webView:willStartInputSession:]):
+
 2018-10-01  Sihui Liu  <sihui_liu@apple.com>
 
         Remove StorageProcess
index 80f86d3..066c580 100644 (file)
@@ -87,10 +87,9 @@ static CGRect rounded(CGRect rect)
 
 @end
 
-static RetainPtr<TestWKWebView> webViewWithAutofocusedInput()
+static RetainPtr<TestWKWebView> webViewWithAutofocusedInput(const RetainPtr<TestInputDelegate>& inputDelegate)
 {
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
-    auto inputDelegate = adoptNS([[TestInputDelegate alloc] init]);
 
     bool doneWaiting = false;
     [inputDelegate setFocusStartsInputSessionPolicyHandler:[&] (WKWebView *, id <_WKFocusedElementInfo>) -> _WKFocusStartsInputSessionPolicy {
@@ -105,8 +104,29 @@ static RetainPtr<TestWKWebView> webViewWithAutofocusedInput()
     return webView;
 }
 
+static RetainPtr<TestWKWebView> webViewWithAutofocusedInput()
+{
+    auto inputDelegate = adoptNS([TestInputDelegate new]);
+    return webViewWithAutofocusedInput(inputDelegate);
+}
+
 namespace TestWebKitAPI {
 
+TEST(KeyboardInputTests, CustomInputViewAndInputAccessoryView)
+{
+    auto inputView = adoptNS([[UIView alloc] init]);
+    auto inputAccessoryView = adoptNS([[UIView alloc] init]);
+    auto inputDelegate = adoptNS([TestInputDelegate new]);
+    [inputDelegate setWillStartInputSessionHandler:[inputView, inputAccessoryView] (WKWebView *, id<_WKFormInputSession> session) {
+        session.customInputView = inputView.get();
+        session.customInputAccessoryView = inputAccessoryView.get();
+    }];
+
+    auto webView = webViewWithAutofocusedInput(inputDelegate);
+    EXPECT_EQ(inputView.get(), [webView firstResponder].inputView);
+    EXPECT_EQ(inputAccessoryView.get(), [webView firstResponder].inputAccessoryView);
+}
+
 TEST(KeyboardInputTests, CanHandleKeyEventInCompletionHandler)
 {
     auto webView = webViewWithAutofocusedInput();
index ff28be6..f9ed482 100644 (file)
 #if WK_API_ENABLED && PLATFORM(IOS)
 
 #import <WebKit/_WKFocusedElementInfo.h>
+#import <WebKit/_WKFormInputSession.h>
 #import <WebKit/_WKInputDelegate.h>
 
 @class WKWebView;
 
 @interface TestInputDelegate : NSObject <_WKInputDelegate>
 @property (nonatomic, copy) _WKFocusStartsInputSessionPolicy (^focusStartsInputSessionPolicyHandler)(WKWebView *, id <_WKFocusedElementInfo>);
+@property (nonatomic, copy) void (^willStartInputSessionHandler)(WKWebView *, id <_WKFormInputSession>);
 @end
 
 #endif
index f0d1d24..a31bf5d 100644 (file)
@@ -32,6 +32,7 @@
 
 @implementation TestInputDelegate {
     BlockPtr<_WKFocusStartsInputSessionPolicy(WKWebView *, id <_WKFocusedElementInfo>)> _focusStartsInputSessionPolicyHandler;
+    BlockPtr<void(WKWebView *, id <_WKFormInputSession>)> _willStartInputSessionHandler;
 }
 
 - (void)setFocusStartsInputSessionPolicyHandler:(_WKFocusStartsInputSessionPolicy (^)(WKWebView *, id <_WKFocusedElementInfo>))handler
     return _focusStartsInputSessionPolicyHandler.get();
 }
 
+- (void)setWillStartInputSessionHandler:(void (^)(WKWebView *, id<_WKFormInputSession>))willStartInputSessionHandler
+{
+    _willStartInputSessionHandler = makeBlockPtr(willStartInputSessionHandler);
+}
+
+- (void (^)(WKWebView *, id<_WKFormInputSession>))willStartInputSessionHandler
+{
+    return _willStartInputSessionHandler.get();
+}
+
 - (_WKFocusStartsInputSessionPolicy)_webView:(WKWebView *)webView decidePolicyForFocusedElement:(id <_WKFocusedElementInfo>)info
 {
     return self.focusStartsInputSessionPolicyHandler ? self.focusStartsInputSessionPolicyHandler(webView, info) : _WKFocusStartsInputSessionPolicyAuto;
 }
 
+- (void)_webView:(WKWebView *)webView willStartInputSession:(id<_WKFormInputSession>)inputSession
+{
+    if (_willStartInputSessionHandler)
+        _willStartInputSessionHandler(webView, inputSession);
+}
+
 @end
 
 #endif // WK_API_ENABLED && PLATFORM(IOS)