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

[iOS][MF] Prevent leaking suggestions

Makes explicit when the custom keyboard views are paused.
Nils last suggestions on reset.
Removes the accessory view from non web urls.
Organizes code in the the form activity handler.
Stops using |lastSuggestions| to gate view controller updates,
|[pause / continue]CustomViewController| is used instead.

Bug: 845472
Change-Id: I751015f9bd2b7b085c15a10fd41fd949dc1fa672
Reviewed-on: https://chromium-review.googlesource.com/c/1355179Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Commit-Queue: Javier Ernesto Flores Robles <javierrobles@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612280}
parent e99bf4a9
...@@ -18,7 +18,8 @@ extern CGFloat const kInputAccessoryHeight; ...@@ -18,7 +18,8 @@ extern CGFloat const kInputAccessoryHeight;
// Creates and manages a custom input accessory view while the user is // Creates and manages a custom input accessory view while the user is
// interacting with a form. Also handles hiding and showing the default // interacting with a form. Also handles hiding and showing the default
// accessory view elements. // accessory view elements. Defaults in paused state and needs to be started by
// calling |continueCustomKeyboardView|.
@interface FormInputAccessoryViewController @interface FormInputAccessoryViewController
: NSObject<FormInputAccessoryConsumer> : NSObject<FormInputAccessoryConsumer>
......
...@@ -78,6 +78,7 @@ CGFloat const kInputAccessoryHeight = 44.0f; ...@@ -78,6 +78,7 @@ CGFloat const kInputAccessoryHeight = 44.0f;
manualFillAccessoryViewControllerDelegate { manualFillAccessoryViewControllerDelegate {
self = [super init]; self = [super init];
if (self) { if (self) {
_paused = YES;
_manualFillAccessoryViewControllerDelegate = _manualFillAccessoryViewControllerDelegate =
manualFillAccessoryViewControllerDelegate; manualFillAccessoryViewControllerDelegate;
if (autofill::features::IsPasswordManualFallbackEnabled()) { if (autofill::features::IsPasswordManualFallbackEnabled()) {
...@@ -209,10 +210,9 @@ CGFloat const kInputAccessoryHeight = 44.0f; ...@@ -209,10 +210,9 @@ CGFloat const kInputAccessoryHeight = 44.0f;
- (void)restoreOriginalKeyboardView { - (void)restoreOriginalKeyboardView {
[self.manualFillAccessoryViewController reset]; [self.manualFillAccessoryViewController reset];
[self restoreOriginalInputAccessoryView]; [self removeCustomInputAccessoryView];
[self.keyboardReplacementView removeFromSuperview]; [self.keyboardReplacementView removeFromSuperview];
self.keyboardReplacementView = nil; self.keyboardReplacementView = nil;
self.paused = NO;
} }
- (void)pauseCustomKeyboardView { - (void)pauseCustomKeyboardView {
...@@ -278,11 +278,6 @@ CGFloat const kInputAccessoryHeight = 44.0f; ...@@ -278,11 +278,6 @@ CGFloat const kInputAccessoryHeight = 44.0f;
[self.grayBackgroundView removeFromSuperview]; [self.grayBackgroundView removeFromSuperview];
} }
// Removes the custom input accessory views and clears the references.
- (void)restoreOriginalInputAccessoryView {
[self removeCustomInputAccessoryView];
}
// This searches in a keyboard view hierarchy for the best candidate to // This searches in a keyboard view hierarchy for the best candidate to
// constrain a view to the keyboard. // constrain a view to the keyboard.
- (UIView*)recursiveGetKeyboardConstraintView:(UIView*)view { - (UIView*)recursiveGetKeyboardConstraintView:(UIView*)view {
......
...@@ -51,6 +51,9 @@ ...@@ -51,6 +51,9 @@
// The object that manages the currently-shown custom accessory view. // The object that manages the currently-shown custom accessory view.
@property(nonatomic, weak) id<FormInputSuggestionsProvider> currentProvider; @property(nonatomic, weak) id<FormInputSuggestionsProvider> currentProvider;
// YES if the first responder is a text input other than the web view.
@property(nonatomic, assign) BOOL editingUIKitTextInput;
// The form input handler. This is in charge of form navigation. // The form input handler. This is in charge of form navigation.
@property(nonatomic, strong) @property(nonatomic, strong)
FormInputAccessoryViewHandler* formInputAccessoryHandler; FormInputAccessoryViewHandler* formInputAccessoryHandler;
...@@ -82,6 +85,10 @@ ...@@ -82,6 +85,10 @@
// Whether suggestions are disabled. // Whether suggestions are disabled.
@property(nonatomic, assign) BOOL suggestionsDisabled; @property(nonatomic, assign) BOOL suggestionsDisabled;
// YES if the latest form activity was made in a form that supports the
// accessory.
@property(nonatomic, assign) BOOL validActivityForAccessoryView;
// The WebState this instance is observing. Can be null. // The WebState this instance is observing. Can be null.
@property(nonatomic, assign) web::WebState* webState; @property(nonatomic, assign) web::WebState* webState;
...@@ -227,10 +234,7 @@ ...@@ -227,10 +234,7 @@
- (void)keyboardWillShowWithHardwareKeyboardAttached:(BOOL)isHardwareKeyboard { - (void)keyboardWillShowWithHardwareKeyboardAttached:(BOOL)isHardwareKeyboard {
self.hardwareKeyboard = isHardwareKeyboard; self.hardwareKeyboard = isHardwareKeyboard;
if (self.lastSuggestions) { [self updateWithProvider:self.lastProvider suggestions:self.lastSuggestions];
[self updateWithProvider:self.lastProvider
suggestions:self.lastSuggestions];
}
} }
- (void)keyboardDidStayOnScreen { - (void)keyboardDidStayOnScreen {
...@@ -249,30 +253,54 @@ ...@@ -249,30 +253,54 @@
didRegisterFormActivity:(const autofill::FormActivityParams&)params didRegisterFormActivity:(const autofill::FormActivityParams&)params
inFrame:(web::WebFrame*)frame { inFrame:(web::WebFrame*)frame {
DCHECK_EQ(_webState, webState); DCHECK_EQ(_webState, webState);
self.validActivityForAccessoryView = NO;
// Return early if |params| is not complete.
if (params.input_missing) {
return;
}
// Return early if the URL can't be verified.
web::URLVerificationTrustLevel trustLevel; web::URLVerificationTrustLevel trustLevel;
const GURL pageURL(webState->GetCurrentURL(&trustLevel)); const GURL pageURL(webState->GetCurrentURL(&trustLevel));
if (params.input_missing || if (trustLevel != web::URLVerificationTrustLevel::kAbsolute) {
trustLevel != web::URLVerificationTrustLevel::kAbsolute || return;
!web::UrlHasWebScheme(pageURL) || !webState->ContentIsHTML()) { }
// Return early, pause and reset if the url is not HTML.
if (!web::UrlHasWebScheme(pageURL) || !webState->ContentIsHTML()) {
[self pauseCustomKeyboardView];
[self reset]; [self reset];
return; return;
} }
// Return early and reset if messaging is enabled but frame is missing or
// can't call JS.
if (autofill::switches::IsAutofillIFrameMessagingEnabled() && if (autofill::switches::IsAutofillIFrameMessagingEnabled() &&
(!frame || !frame->CanCallJavaScriptFunction())) { (!frame || !frame->CanCallJavaScriptFunction())) {
[self reset]; [self reset];
return; return;
} }
self.validActivityForAccessoryView = YES;
[self continueCustomKeyboardView];
NSString* frameID;
if (frame) {
frameID = base::SysUTF8ToNSString(frame->GetFrameId());
} else {
frameID = base::SysUTF8ToNSString(params.frame_id);
}
[self.formInputAccessoryHandler setLastFocusFormActivityWebFrameID:frameID];
[self synchronizeNavigationControls];
// Don't look for suggestions in the next events.
if (params.type == "blur" || params.type == "change" || if (params.type == "blur" || params.type == "change" ||
params.type == "form_changed") { params.type == "form_changed") {
return; return;
} }
[self.formInputAccessoryHandler
setLastFocusFormActivityWebFrameID:base::SysUTF8ToNSString(
params.frame_id)];
[self synchronizeNavigationControls];
[self retrieveSuggestionsForForm:params webState:webState]; [self retrieveSuggestionsForForm:params webState:webState];
} }
...@@ -296,7 +324,7 @@ ...@@ -296,7 +324,7 @@
- (void)webStateWasShown:(web::WebState*)webState { - (void)webStateWasShown:(web::WebState*)webState {
DCHECK_EQ(_webState, webState); DCHECK_EQ(_webState, webState);
[self.consumer continueCustomKeyboardView]; [self continueCustomKeyboardView];
} }
- (void)webStateWasHidden:(web::WebState*)webState { - (void)webStateWasHidden:(web::WebState*)webState {
...@@ -311,7 +339,7 @@ ...@@ -311,7 +339,7 @@
if (IsIPadIdiom()) { if (IsIPadIdiom()) {
[self reset]; [self reset];
} else { } else {
[self.consumer pauseCustomKeyboardView]; [self pauseCustomKeyboardView];
} }
} }
...@@ -363,6 +391,32 @@ ...@@ -363,6 +391,32 @@
#pragma mark - Private #pragma mark - Private
// Tells the consumer to pause the custom keyboard view.
- (void)pauseCustomKeyboardView {
[self.consumer pauseCustomKeyboardView];
}
// Tells the consumer to continue the custom keyboard view if the last activity
// is valid, the web state is visible, and there is no other text input.
- (void)continueCustomKeyboardView {
// Return early if the form is not a supported one.
if (!self.validActivityForAccessoryView) {
return;
}
// Return early if the current webstate is not visible.
if (!self.webState || !self.webState->IsVisible()) {
return;
}
// Return early if the current text input is not the web view.
if (self.editingUIKitTextInput) {
return;
}
[self.consumer continueCustomKeyboardView];
}
// Update the status of the consumer form navigation buttons to match the // Update the status of the consumer form navigation buttons to match the
// handler state. // handler state.
- (void)synchronizeNavigationControls { - (void)synchronizeNavigationControls {
...@@ -407,6 +461,9 @@ ...@@ -407,6 +461,9 @@
// Resets the current provider, the consumer view and the navigation handler. As // Resets the current provider, the consumer view and the navigation handler. As
// well as reenables suggestions. // well as reenables suggestions.
- (void)reset { - (void)reset {
self.lastSuggestions = nil;
self.lastProvider = nil;
[self.consumer restoreOriginalKeyboardView]; [self.consumer restoreOriginalKeyboardView];
[self.formInputAccessoryHandler reset]; [self.formInputAccessoryHandler reset];
...@@ -511,13 +568,15 @@ queryViewBlockForProvider:(id<FormInputSuggestionsProvider>)provider ...@@ -511,13 +568,15 @@ queryViewBlockForProvider:(id<FormInputSuggestionsProvider>)provider
// begins editing, pause the consumer so it doesn't present the custom view over // begins editing, pause the consumer so it doesn't present the custom view over
// the keyboard. // the keyboard.
- (void)handleTextInputDidBeginEditing:(NSNotification*)notification { - (void)handleTextInputDidBeginEditing:(NSNotification*)notification {
[self.consumer pauseCustomKeyboardView]; self.editingUIKitTextInput = YES;
[self pauseCustomKeyboardView];
} }
// When any text field or text view (e.g. omnibox, settings, card unmask dialog) // When any text field or text view (e.g. omnibox, settings, card unmask dialog)
// ends editing, continue presenting. // ends editing, continue presenting.
- (void)handleTextInputDidEndEditing:(NSNotification*)notification { - (void)handleTextInputDidEndEditing:(NSNotification*)notification {
[self.consumer continueCustomKeyboardView]; self.editingUIKitTextInput = NO;
[self continueCustomKeyboardView];
} }
#pragma mark - PasswordFetcherDelegate #pragma mark - PasswordFetcherDelegate
......
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