[ios] update suggestions after password generation

Force a focus event (js) which will propagate back to the suggestions mediator who
will update the suggestion bar.  Applied to both Cancel and using suggested password.

Removed call to completion when suggesting a password, because form filling is
not complete, and we want the keyboard to stay (or come back) up.

Bug: 964941
Change-Id: I31900792b0c3452913cb71c31a6c89b502a0b27b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1620640
Commit-Queue: David Jean <djean@chromium.org>
Reviewed-by: Vadym Doroshenko <dvadym@chromium.org>
Cr-Commit-Position: refs/heads/master@{#662107}
diff --git a/components/password_manager/ios/js_password_manager.h b/components/password_manager/ios/js_password_manager.h
index c22d06a..f73b5b17 100644
--- a/components/password_manager/ios/js_password_manager.h
+++ b/components/password_manager/ios/js_password_manager.h
@@ -75,6 +75,13 @@
             generatedPassword:(NSString*)generatedPassword
             completionHandler:(void (^)(BOOL))completionHandler;
 
+// Finds given field, identified by |fieldIdentifier| in the given |formName|
+// and focus it, which should trigger a form focus event. If not nil, calls
+// |completionHandler| with YES if the field was found and event was dispatched.
+- (void)focusOnForm:(NSString*)formName
+      fieldIdentifier:(NSString*)fieldIdentifier
+    completionHandler:(void (^)(BOOL))completionHandler;
+
 // Designated initializer. |receiver| should not be nil.
 - (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver
     NS_DESIGNATED_INITIALIZER;
diff --git a/components/password_manager/ios/js_password_manager.mm b/components/password_manager/ios/js_password_manager.mm
index 56eee97..8a15e01 100644
--- a/components/password_manager/ios/js_password_manager.mm
+++ b/components/password_manager/ios/js_password_manager.mm
@@ -139,4 +139,18 @@
              }];
 }
 
+- (void)focusOnForm:(NSString*)formName
+      fieldIdentifier:(NSString*)fieldIdentifier
+    completionHandler:(void (^)(BOOL))completionHandler {
+  NSString* script = [NSString stringWithFormat:@"__gCrWeb.passwords."
+                                                @"focusOnFormField(%@, %@)",
+                                                JSONEscape(formName),
+                                                JSONEscape(fieldIdentifier)];
+  [_receiver executeJavaScript:script
+             completionHandler:^(id result, NSError*) {
+               if (completionHandler)
+                 completionHandler([result isEqual:@YES]);
+             }];
+}
+
 @end
diff --git a/components/password_manager/ios/password_form_helper.h b/components/password_manager/ios/password_form_helper.h
index f74c69a9..bbb80b2 100644
--- a/components/password_manager/ios/password_form_helper.h
+++ b/components/password_manager/ios/password_form_helper.h
@@ -98,6 +98,13 @@
                   (void (^)(BOOL found,
                             const autofill::FormData& form))completionHandler;
 
+// Finds given field, identified by |fieldIdentifier| in the given |formName|
+// and focus it, which should trigger a form focus event. Invokes
+// |completionHandler| when finished with YES if successful and NO otherwise.
+- (void)focusOnForm:(NSString*)formName
+      fieldIdentifier:(NSString*)fieldIdentifier
+    completionHandler:(nullable void (^)(BOOL))completionHandler;
+
 // Creates a instance with the given WebState, observer and delegate.
 - (instancetype)initWithWebState:(web::WebState*)webState
                         delegate:
diff --git a/components/password_manager/ios/password_form_helper.mm b/components/password_manager/ios/password_form_helper.mm
index 77d92a7..77a0aef 100644
--- a/components/password_manager/ios/password_form_helper.mm
+++ b/components/password_manager/ios/password_form_helper.mm
@@ -459,4 +459,12 @@
                     completionHandler:extractFormDataCompletionHandler];
 }
 
+- (void)focusOnForm:(NSString*)formName
+      fieldIdentifier:(NSString*)fieldIdentifier
+    completionHandler:(nullable void (^)(BOOL))completionHandler {
+  [self.jsPasswordManager focusOnForm:formName
+                      fieldIdentifier:fieldIdentifier
+                    completionHandler:completionHandler];
+}
+
 @end
diff --git a/components/password_manager/ios/resources/password_controller.js b/components/password_manager/ios/resources/password_controller.js
index 7599dc1..48c04b46 100644
--- a/components/password_manager/ios/resources/password_controller.js
+++ b/components/password_manager/ios/resources/password_controller.js
@@ -235,6 +235,25 @@
 };
 
 /**
+ * Finds given field, identified by |fieldIdentifier| in the given |formName|
+ * and focus it, which should trigger a form focus event.
+ * @return {boolean} if field was found and focused.
+ */
+__gCrWeb.passwords['focusOnFormField'] = function(formName, fieldIdentifier) {
+  var form = __gCrWeb.form.getFormElementFromIdentifier(formName);
+  if (!form)
+    return false;
+  var inputs = getFormInputElements_(form);
+  var field =
+      findInputByFieldIdentifier_(inputs, fieldIdentifier);
+  if (!field)
+    return false;
+  __gCrWeb.fill.createAndDispatchHTMLEvent(
+        field, field.value, 'focus', true, false);
+  return true;
+};
+
+/**
  * Given a description of a form (origin, action and input fields),
  * finds that form on the page and fills in the specified username
  * and password.
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index beeab912..2b1add5 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -479,11 +479,10 @@
       return;
     }
     case autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY: {
+      // Don't call completion because current siggestion state should remain
+      // whether user injects a generated password or cancels.
       [self generatePasswordForFormName:formName
-                      completionHandler:^(BOOL injected) {
-                        if (injected)
-                          completion();
-                      }];
+                        fieldIdentifier:fieldIdentifier];
       LogSuggestionClicked(PasswordSuggestionType::SUGGESTED);
       return;
     }
@@ -764,7 +763,7 @@
 }
 
 - (void)generatePasswordForFormName:(NSString*)formName
-                  completionHandler:(void (^)(BOOL))completionHandler {
+                    fieldIdentifier:(NSString*)fieldIdentifier {
   if (![self getFormForGenerationFromFormName:formName])
     return;
 
@@ -798,6 +797,15 @@
 
   __weak PasswordController* weakSelf = self;
 
+  auto restoreFocus = ^{
+    [weakSelf generatePasswordPopupDismissed];
+    // Suggestion are still visible but they lost their state, so by forcing
+    // a focus event on the current field, it will reset the suggestions.
+    [weakSelf.formHelper focusOnForm:formName
+                     fieldIdentifier:fieldIdentifier
+                   completionHandler:nil];
+  };
+
   [self.actionSheetCoordinator
       addItemWithTitle:GetNSString(IDS_IOS_USE_SUGGESTED_PASSWORD)
                 action:^{
@@ -805,18 +813,12 @@
                       injectGeneratedPasswordForFormName:formName
                                        generatedPassword:
                                            weakSelf.generatedPotentialPassword
-                                       completionHandler:completionHandler];
-                  [weakSelf generatePasswordPopupDismissed];
+                                       completionHandler:restoreFocus];
                 }
                  style:UIAlertActionStyleDefault];
 
   [self.actionSheetCoordinator addItemWithTitle:GetNSString(IDS_CANCEL)
-                                         action:^{
-                                           if (completionHandler)
-                                             completionHandler(NO);
-                                           [weakSelf
-                                               generatePasswordPopupDismissed];
-                                         }
+                                         action:restoreFocus
                                           style:UIAlertActionStyleCancel];
 
   // Set 'suggest' as preferred action, as per UX.
@@ -861,7 +863,7 @@
 
 - (void)injectGeneratedPasswordForFormName:(NSString*)formName
                          generatedPassword:(NSString*)generatedPassword
-                         completionHandler:(void (^)(BOOL))completionHandler {
+                         completionHandler:(void (^)())completionHandler {
   const autofill::NewPasswordFormGenerationData* generation_data =
       [self getFormForGenerationFromFormName:formName];
   if (!generation_data)
@@ -889,7 +891,7 @@
       self.passwordGeneratedIdentifier = newPasswordIdentifier;
     }
     if (completionHandler)
-      completionHandler(YES);
+      completionHandler();
   };
 
   [self.formHelper fillPasswordForm:formName