diff options
Diffstat (limited to 'chromium/ui/keyboard/keyboard_controller.cc')
-rw-r--r-- | chromium/ui/keyboard/keyboard_controller.cc | 85 |
1 files changed, 67 insertions, 18 deletions
diff --git a/chromium/ui/keyboard/keyboard_controller.cc b/chromium/ui/keyboard/keyboard_controller.cc index 76a576bfe09..b9ba7f519ef 100644 --- a/chromium/ui/keyboard/keyboard_controller.cc +++ b/chromium/ui/keyboard/keyboard_controller.cc @@ -12,6 +12,7 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" @@ -25,6 +26,7 @@ #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/display/types/display_constants.h" +#include "ui/events/base_event_utils.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/path.h" @@ -36,6 +38,7 @@ #include "ui/keyboard/keyboard_ui.h" #include "ui/keyboard/keyboard_util.h" #include "ui/keyboard/notification_manager.h" +#include "ui/keyboard/queued_container_type.h" #include "ui/wm/core/window_animations.h" #if defined(OS_CHROMEOS) @@ -51,6 +54,13 @@ constexpr int kHideKeyboardDelayMs = 100; // intermediate state for more than 5 seconds. constexpr int kReportLingeringStateDelayMs = 5000; +// Delay threshold after the keyboard enters the WILL_HIDE state. If text focus +// is regained during this threshold, the keyboard will show again, even if it +// is an asynchronous event. This is for the benefit of things like login flow +// where the password field may get text focus after an animation that plays +// after the user enters their username. +constexpr int kTransientBlurThresholdMs = 3500; + // State transition diagram (document linked from crbug.com/719905) bool isAllowedStateTransition(keyboard::KeyboardControllerState from, keyboard::KeyboardControllerState to) { @@ -202,12 +212,11 @@ KeyboardController::KeyboardController(std::unique_ptr<KeyboardUI> ui, show_on_content_update_(false), keyboard_locked_(false), state_(KeyboardControllerState::UNKNOWN), - enqueued_container_type_(ContainerType::FULL_WIDTH), weak_factory_report_lingering_state_(this), weak_factory_will_hide_(this) { ui_->GetInputMethod()->AddObserver(this); ui_->SetController(this); - SetContainerBehaviorInternal(enqueued_container_type_); + SetContainerBehaviorInternal(ContainerType::FULL_WIDTH); ChangeState(KeyboardControllerState::INITIAL); } @@ -385,11 +394,8 @@ void KeyboardController::HideKeyboard(HideReason reason) { } void KeyboardController::HideAnimationFinished() { - if (state_ != KeyboardControllerState::HIDDEN) - return; - - if (enqueued_container_type_ != container_behavior_->GetType()) { - SetContainerBehaviorInternal(enqueued_container_type_); + if (state_ == KeyboardControllerState::HIDDEN && queued_container_type_) { + SetContainerBehaviorInternal(queued_container_type_->container_type()); ShowKeyboard(false /* lock */); } } @@ -498,17 +504,36 @@ void KeyboardController::OnTextInputStateChanged( return; } } else { - // Abort a pending keyboard hide. - if (WillHideKeyboard()) - ChangeState(KeyboardControllerState::SHOWN); + switch (state_) { + case KeyboardControllerState::WILL_HIDE: + // Abort a pending keyboard hide. + ChangeState(KeyboardControllerState::SHOWN); + return; + case KeyboardControllerState::HIDDEN: + if (focused) + ShowKeyboardIfWithinTransientBlurThreshold(); + return; + default: + break; + } // Do not explicitly show the Virtual keyboard unless it is in the process - // of hiding. Instead, the virtual keyboard is shown in response to a user - // gesture (mouse or touch) that is received while an element has input - // focus. Showing the keyboard requires an explicit call to - // OnShowImeIfNeeded. + // of hiding or the hide duration was very short (transient blur). Instead, + // the virtual keyboard is shown in response to a user gesture (mouse or + // touch) that is received while an element has input focus. Showing the + // keyboard requires an explicit call to OnShowImeIfNeeded. } } +void KeyboardController::ShowKeyboardIfWithinTransientBlurThreshold() { + static const base::TimeDelta kTransientBlurThreshold = + base::TimeDelta::FromMilliseconds(kTransientBlurThresholdMs); + + const base::Time now = base::Time::Now(); + const base::TimeDelta time_since_last_blur = now - time_of_last_blur_; + if (time_since_last_blur < kTransientBlurThreshold) + ShowKeyboard(false); +} + void KeyboardController::OnShowImeIfNeeded() { // Calling |ShowKeyboardInternal| may move the keyboard to another display. if (IsKeyboardEnabled() && !keyboard_locked()) @@ -624,6 +649,10 @@ void KeyboardController::PopulateKeyboardContent(int64_t display_id, container_behavior_->DoShowingAnimation(container_.get(), &settings); + // the queued container behavior will notify JS to change layout when it + // gets destroyed. + queued_container_type_ = nullptr; + ChangeState(KeyboardControllerState::SHOWN); NotifyKeyboardBoundsChangingAndEnsureCaretInWorkArea(); } @@ -678,6 +707,8 @@ void KeyboardController::ChangeState(KeyboardControllerState state) { if (state_ == state) return; + KeyboardControllerState original_state = state_; + state_ = state; if (state != KeyboardControllerState::WILL_HIDE) @@ -691,11 +722,16 @@ void KeyboardController::ChangeState(KeyboardControllerState state) { switch (state_) { case KeyboardControllerState::LOADING_EXTENSION: case KeyboardControllerState::WILL_HIDE: + if (state_ == KeyboardControllerState::WILL_HIDE && + original_state == KeyboardControllerState::SHOWN) { + time_of_last_blur_ = base::Time::Now(); + } base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::BindOnce(&KeyboardController::ReportLingeringState, weak_factory_report_lingering_state_.GetWeakPtr()), base::TimeDelta::FromMilliseconds(kReportLingeringStateDelayMs)); + break; default: // Do nothing @@ -737,18 +773,31 @@ bool KeyboardController::IsOverscrollAllowed() const { } void KeyboardController::HandlePointerEvent(const ui::LocatedEvent& event) { - container_behavior_->HandlePointerEvent(event); + container_behavior_->HandlePointerEvent( + event, container_->GetRootWindow()->bounds()); } -void KeyboardController::SetContainerType(const ContainerType type) { - if (container_behavior_->GetType() == type) + +void KeyboardController::SetContainerType( + const ContainerType type, + base::OnceCallback<void(bool)> callback) { + if (container_behavior_->GetType() == type) { + std::move(callback).Run(false); return; + } - enqueued_container_type_ = type; if (state_ == KeyboardControllerState::SHOWN) { + // Keyboard is already shown. Hiding the keyboard at first then switching + // container type. + queued_container_type_ = + std::make_unique<QueuedContainerType>(this, type, std::move(callback)); HideKeyboard(HIDE_REASON_AUTOMATIC); } else { + // Keyboard is hidden. Switching the container type immediately and invoking + // the passed callback now. SetContainerBehaviorInternal(type); + DCHECK(GetActiveContainerType() == type); + std::move(callback).Run(true /* change_successful */); } } |