1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ash/keyboard/ui/keyboard_ui_controller.h"
6 
7 #include <set>
8 
9 #include "ash/keyboard/ui/container_floating_behavior.h"
10 #include "ash/keyboard/ui/container_full_width_behavior.h"
11 #include "ash/keyboard/ui/display_util.h"
12 #include "ash/keyboard/ui/keyboard_layout_manager.h"
13 #include "ash/keyboard/ui/keyboard_ui.h"
14 #include "ash/keyboard/ui/keyboard_ui_factory.h"
15 #include "ash/keyboard/ui/keyboard_util.h"
16 #include "ash/keyboard/ui/notification_manager.h"
17 #include "ash/keyboard/ui/queued_container_type.h"
18 #include "ash/keyboard/ui/queued_display_change.h"
19 #include "ash/keyboard/ui/shaped_window_targeter.h"
20 #include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
21 #include "ash/public/cpp/keyboard/keyboard_switches.h"
22 #include "base/bind.h"
23 #include "base/command_line.h"
24 #include "base/macros.h"
25 #include "base/metrics/histogram_functions.h"
26 #include "base/metrics/histogram_macros.h"
27 #include "base/stl_util.h"
28 #include "base/threading/thread_task_runner_handle.h"
29 #include "base/time/time.h"
30 #include "ui/aura/client/aura_constants.h"
31 #include "ui/aura/env.h"
32 #include "ui/aura/window.h"
33 #include "ui/aura/window_delegate.h"
34 #include "ui/aura/window_observer.h"
35 #include "ui/base/cursor/cursor.h"
36 #include "ui/base/hit_test.h"
37 #include "ui/base/ime/text_input_client.h"
38 #include "ui/base/ime/text_input_flags.h"
39 #include "ui/compositor/layer_animation_observer.h"
40 #include "ui/compositor/scoped_layer_animation_settings.h"
41 #include "ui/display/types/display_constants.h"
42 #include "ui/events/base_event_utils.h"
43 #include "ui/events/gestures/gesture_recognizer.h"
44 #include "ui/gfx/geometry/rect.h"
45 #include "ui/gfx/geometry/vector2d.h"
46 #include "ui/ozone/public/input_controller.h"
47 #include "ui/ozone/public/ozone_platform.h"
48 #include "ui/wm/core/coordinate_conversion.h"
49 #include "ui/wm/core/window_animations.h"
50 
51 namespace keyboard {
52 
53 namespace {
54 
55 // Owned by ash::Shell.
56 KeyboardUIController* g_keyboard_controller = nullptr;
57 
58 // How long the keyboard stays in WILL_HIDE state before moving to HIDDEN.
59 constexpr base::TimeDelta kHideKeyboardDelay =
60     base::TimeDelta::FromMilliseconds(100);
61 
62 // Reports an error histogram if the keyboard state is lingering in an
63 // intermediate state for more than 5 seconds.
64 constexpr base::TimeDelta kReportLingeringStateDelay =
65     base::TimeDelta::FromMilliseconds(5000);
66 
67 // Delay threshold after the keyboard enters the WILL_HIDE state. If text focus
68 // is regained during this threshold, the keyboard will show again, even if it
69 // is an asynchronous event. This is for the benefit of things like login flow
70 // where the password field may get text focus after an animation that plays
71 // after the user enters their username.
72 constexpr base::TimeDelta kTransientBlurThreshold =
73     base::TimeDelta::FromMilliseconds(3500);
74 
SetTouchEventLogging(bool enable)75 void SetTouchEventLogging(bool enable) {
76   ui::InputController* controller =
77       ui::OzonePlatform::GetInstance()->GetInputController();
78   if (controller)
79     controller->SetTouchEventLoggingEnabled(enable);
80 }
81 
82 // An enumeration of different keyboard control events that should be logged.
83 // These values are persisted to logs. Entries should not be renumbered and
84 // numeric values should never be reused.
85 enum class KeyboardControlEvent {
86   kShow = 0,
87   kHideAuto = 1,
88   kHideUser = 2,
89   kMaxValue = kHideUser
90 };
91 
LogKeyboardControlEvent(KeyboardControlEvent event)92 void LogKeyboardControlEvent(KeyboardControlEvent event) {
93   UMA_HISTOGRAM_ENUMERATION("VirtualKeyboard.KeyboardControlEvent", event);
94 }
95 
96 class InputMethodKeyboardController : public ui::InputMethodKeyboardController {
97  public:
InputMethodKeyboardController(KeyboardUIController * keyboard_ui_controller)98   explicit InputMethodKeyboardController(
99       KeyboardUIController* keyboard_ui_controller)
100       : keyboard_ui_controller_(keyboard_ui_controller) {}
101 
102   ~InputMethodKeyboardController() override = default;
103 
104   // ui::InputMethodKeyboardController
DisplayVirtualKeyboard()105   bool DisplayVirtualKeyboard() override {
106     // Calling |ShowKeyboardInternal| may move the keyboard to another display.
107     if (keyboard_ui_controller_->IsEnabled() &&
108         !keyboard_ui_controller_->keyboard_locked()) {
109       keyboard_ui_controller_->ShowKeyboard(false /* locked */);
110       return true;
111     }
112     return false;
113   }
114 
DismissVirtualKeyboard()115   void DismissVirtualKeyboard() override {
116     keyboard_ui_controller_->HideKeyboardByUser();
117   }
118 
AddObserver(ui::InputMethodKeyboardControllerObserver * observer)119   void AddObserver(
120       ui::InputMethodKeyboardControllerObserver* observer) override {
121     // TODO(shend): Implement.
122   }
123 
RemoveObserver(ui::InputMethodKeyboardControllerObserver * observer)124   void RemoveObserver(
125       ui::InputMethodKeyboardControllerObserver* observer) override {
126     // TODO(shend): Implement.
127   }
128 
IsKeyboardVisible()129   bool IsKeyboardVisible() override {
130     return keyboard_ui_controller_->IsKeyboardVisible();
131   }
132 
133  private:
134   KeyboardUIController* keyboard_ui_controller_;
135 };
136 
137 }  // namespace
138 
139 // Observer for both keyboard show and hide animations. It should be owned by
140 // KeyboardUIController.
141 class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
142  public:
CallbackAnimationObserver(base::OnceClosure callback)143   explicit CallbackAnimationObserver(base::OnceClosure callback)
144       : callback_(std::move(callback)) {}
145 
146  private:
147   // ui::ImplicitAnimationObserver:
OnImplicitAnimationsCompleted()148   void OnImplicitAnimationsCompleted() override {
149     if (WasAnimationAbortedForProperty(ui::LayerAnimationElement::TRANSFORM) ||
150         WasAnimationAbortedForProperty(ui::LayerAnimationElement::OPACITY)) {
151       return;
152     }
153     DCHECK(
154         WasAnimationCompletedForProperty(ui::LayerAnimationElement::TRANSFORM));
155     DCHECK(
156         WasAnimationCompletedForProperty(ui::LayerAnimationElement::OPACITY));
157     std::move(callback_).Run();
158   }
159 
160   base::OnceClosure callback_;
161 
162   DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
163 };
164 
KeyboardUIController()165 KeyboardUIController::KeyboardUIController()
166     : input_method_keyboard_controller_(
167           std::make_unique<InputMethodKeyboardController>(this)) {
168   DCHECK_EQ(g_keyboard_controller, nullptr);
169   g_keyboard_controller = this;
170 }
171 
~KeyboardUIController()172 KeyboardUIController::~KeyboardUIController() {
173   DCHECK(g_keyboard_controller);
174   DCHECK(!ui_) << "Keyboard UI must be destroyed before KeyboardUIController "
175                   "is destroyed";
176   g_keyboard_controller = nullptr;
177 }
178 
179 // static
Get()180 KeyboardUIController* KeyboardUIController::Get() {
181   DCHECK(g_keyboard_controller);
182   return g_keyboard_controller;
183 }
184 
185 // static
HasInstance()186 bool KeyboardUIController::HasInstance() {
187   return g_keyboard_controller;
188 }
189 
Initialize(std::unique_ptr<KeyboardUIFactory> ui_factory,KeyboardLayoutDelegate * layout_delegate)190 void KeyboardUIController::Initialize(
191     std::unique_ptr<KeyboardUIFactory> ui_factory,
192     KeyboardLayoutDelegate* layout_delegate) {
193   DCHECK(ui_factory);
194   DCHECK(layout_delegate);
195 
196   ui_factory_ = std::move(ui_factory);
197   layout_delegate_ = layout_delegate;
198 
199   DCHECK(!IsKeyboardEnableRequested());
200 }
201 
Shutdown()202 void KeyboardUIController::Shutdown() {
203   keyboard_enable_flags_.clear();
204   EnableFlagsChanged();
205 
206   DCHECK(!IsKeyboardEnableRequested());
207   DisableKeyboard();
208 }
209 
EnableKeyboard()210 void KeyboardUIController::EnableKeyboard() {
211   if (ui_)
212     return;
213 
214   ui_ = ui_factory_->CreateKeyboardUI();
215   DCHECK(ui_);
216 
217   show_on_keyboard_window_load_ = false;
218   keyboard_locked_ = false;
219   DCHECK_EQ(model_.state(), KeyboardUIState::kInitial);
220   ui_->SetController(this);
221   SetContainerBehaviorInternal(ContainerType::kFullWidth);
222   visual_bounds_in_root_ = gfx::Rect();
223   time_of_last_blur_ = base::Time::UnixEpoch();
224   UpdateInputMethodObserver();
225 
226   ActivateKeyboardInContainer(
227       layout_delegate_->GetContainerForDefaultDisplay());
228 
229   // Start preloading the virtual keyboard UI in the background, so that it
230   // shows up faster when needed.
231   LoadKeyboardWindowInBackground();
232 
233   // Notify observers after the keyboard window has a root window.
234   for (auto& observer : observer_list_)
235     observer.OnKeyboardEnabledChanged(true);
236 }
237 
DisableKeyboard()238 void KeyboardUIController::DisableKeyboard() {
239   if (!ui_)
240     return;
241 
242   if (parent_container_)
243     DeactivateKeyboard();
244 
245   aura::Window* keyboard_window = GetKeyboardWindow();
246   if (keyboard_window)
247     keyboard_window->RemoveObserver(this);
248 
249   // Return to the INITIAL state to ensure that transitions entering a state
250   // is equal to transitions leaving the state.
251   if (model_.state() != KeyboardUIState::kInitial)
252     ChangeState(KeyboardUIState::kInitial);
253 
254   // TODO(https://crbug.com/731537): Move KeyboardUIController members into a
255   // subobject so we can just put this code into the subobject destructor.
256   queued_display_change_.reset();
257   queued_container_type_.reset();
258   container_behavior_.reset();
259   animation_observer_.reset();
260 
261   ime_observer_.RemoveAll();
262   ui_->SetController(nullptr);
263   ui_.reset();
264 
265   // Notify observers after |ui_| is reset so that IsEnabled() is false.
266   for (auto& observer : observer_list_)
267     observer.OnKeyboardEnabledChanged(false);
268 }
269 
ActivateKeyboardInContainer(aura::Window * parent)270 void KeyboardUIController::ActivateKeyboardInContainer(aura::Window* parent) {
271   DCHECK(parent);
272   DCHECK(!parent_container_);
273   parent_container_ = parent;
274   // Observe changes to root window bounds.
275   parent_container_->GetRootWindow()->AddObserver(this);
276 
277   UpdateInputMethodObserver();
278 
279   if (GetKeyboardWindow()) {
280     DCHECK(!GetKeyboardWindow()->parent());
281     parent_container_->AddChild(GetKeyboardWindow());
282   }
283 }
284 
DeactivateKeyboard()285 void KeyboardUIController::DeactivateKeyboard() {
286   DCHECK(parent_container_);
287 
288   // Ensure the keyboard is not visible before deactivating it.
289   HideKeyboardExplicitlyBySystem();
290 
291   aura::Window* keyboard_window = GetKeyboardWindow();
292   if (keyboard_window) {
293     keyboard_window->RemovePreTargetHandler(&event_handler_);
294     if (keyboard_window->parent()) {
295       DCHECK_EQ(parent_container_, keyboard_window->parent());
296       parent_container_->RemoveChild(keyboard_window);
297     }
298   }
299   parent_container_->GetRootWindow()->RemoveObserver(this);
300   parent_container_ = nullptr;
301 }
302 
GetKeyboardWindow() const303 aura::Window* KeyboardUIController::GetKeyboardWindow() const {
304   return ui_ ? ui_->GetKeyboardWindow() : nullptr;
305 }
306 
GetGestureConsumer() const307 ui::GestureConsumer* KeyboardUIController::GetGestureConsumer() const {
308   return ui_ ? ui_->GetGestureConsumer() : nullptr;
309 }
310 
GetRootWindow() const311 aura::Window* KeyboardUIController::GetRootWindow() const {
312   return parent_container_ ? parent_container_->GetRootWindow() : nullptr;
313 }
314 
MoveToParentContainer(aura::Window * parent)315 void KeyboardUIController::MoveToParentContainer(aura::Window* parent) {
316   DCHECK(parent);
317   if (parent_container_ == parent)
318     return;
319 
320   TRACE_EVENT0("vk", "MoveKeyboardToDisplayInternal");
321 
322   DeactivateKeyboard();
323   ActivateKeyboardInContainer(parent);
324 }
325 
326 // private
NotifyKeyboardBoundsChanging(const gfx::Rect & new_bounds_in_root)327 void KeyboardUIController::NotifyKeyboardBoundsChanging(
328     const gfx::Rect& new_bounds_in_root) {
329   gfx::Rect occluded_bounds_in_screen;
330   aura::Window* window = GetKeyboardWindow();
331   if (window && window->IsVisible()) {
332     visual_bounds_in_root_ = new_bounds_in_root;
333 
334     // |visual_bounds_in_root_| affects the result of
335     // GetWorkspaceOccludedBoundsInScreen. Calculate |occluded_bounds_in_screen|
336     // after updating |visual_bounds_in_root_|.
337     // TODO(andrewxu): Add the unit test case for issue 960174.
338     occluded_bounds_in_screen = GetWorkspaceOccludedBoundsInScreen();
339 
340     // TODO(https://crbug.com/943446): Use screen bounds for visual bounds.
341     notification_manager_.SendNotifications(
342         container_behavior_->OccludedBoundsAffectWorkspaceLayout(),
343         new_bounds_in_root, occluded_bounds_in_screen, observer_list_);
344   } else {
345     visual_bounds_in_root_ = gfx::Rect();
346     occluded_bounds_in_screen = GetWorkspaceOccludedBoundsInScreen();
347   }
348 
349   EnsureCaretInWorkArea(occluded_bounds_in_screen);
350 }
351 
SetKeyboardWindowBounds(const gfx::Rect & new_bounds_in_root)352 void KeyboardUIController::SetKeyboardWindowBounds(
353     const gfx::Rect& new_bounds_in_root) {
354   ui::LayerAnimator* animator = GetKeyboardWindow()->layer()->GetAnimator();
355   // Stops previous animation if a window resize is requested during animation.
356   if (animator->is_animating())
357     animator->StopAnimating();
358 
359   GetKeyboardWindow()->SetBounds(new_bounds_in_root);
360 }
361 
NotifyKeyboardWindowLoaded()362 void KeyboardUIController::NotifyKeyboardWindowLoaded() {
363   const bool should_show = show_on_keyboard_window_load_;
364   if (model_.state() == KeyboardUIState::kLoading)
365     ChangeState(KeyboardUIState::kHidden);
366   if (should_show) {
367     // The window height is set to 0 initially or before switch to an IME in a
368     // different extension. Virtual keyboard window may wait for this bounds
369     // change to correctly animate in.
370     if (keyboard_locked_) {
371       // Do not move the keyboard to another display after switch to an IME in
372       // a different extension.
373       ShowKeyboardInDisplay(
374           display_util_.GetNearestDisplayToWindow(GetKeyboardWindow()));
375     } else {
376       ShowKeyboard(false /* lock */);
377     }
378   }
379 }
380 
Reload()381 void KeyboardUIController::Reload() {
382   if (!GetKeyboardWindow())
383     return;
384 
385   ui_->ReloadKeyboardIfNeeded();
386 }
387 
RebuildKeyboardIfEnabled()388 void KeyboardUIController::RebuildKeyboardIfEnabled() {
389   if (!IsEnabled())
390     return;
391 
392   DisableKeyboard();
393   EnableKeyboard();
394 }
395 
AddObserver(ash::KeyboardControllerObserver * observer)396 void KeyboardUIController::AddObserver(
397     ash::KeyboardControllerObserver* observer) {
398   observer_list_.AddObserver(observer);
399 }
400 
HasObserver(ash::KeyboardControllerObserver * observer) const401 bool KeyboardUIController::HasObserver(
402     ash::KeyboardControllerObserver* observer) const {
403   return observer_list_.HasObserver(observer);
404 }
405 
RemoveObserver(ash::KeyboardControllerObserver * observer)406 void KeyboardUIController::RemoveObserver(
407     ash::KeyboardControllerObserver* observer) {
408   observer_list_.RemoveObserver(observer);
409 }
410 
UpdateKeyboardConfig(const KeyboardConfig & config)411 bool KeyboardUIController::UpdateKeyboardConfig(const KeyboardConfig& config) {
412   if (config == keyboard_config_)
413     return false;
414   keyboard_config_ = config;
415   if (IsEnabled())
416     NotifyKeyboardConfigChanged();
417   return true;
418 }
419 
SetEnableFlag(KeyboardEnableFlag flag)420 void KeyboardUIController::SetEnableFlag(KeyboardEnableFlag flag) {
421   if (!base::Contains(keyboard_enable_flags_, flag))
422     keyboard_enable_flags_.insert(flag);
423 
424   // If there is a flag that is mutually exclusive with |flag|, clear it.
425   switch (flag) {
426     case KeyboardEnableFlag::kPolicyEnabled:
427       keyboard_enable_flags_.erase(KeyboardEnableFlag::kPolicyDisabled);
428       break;
429     case KeyboardEnableFlag::kPolicyDisabled:
430       keyboard_enable_flags_.erase(KeyboardEnableFlag::kPolicyEnabled);
431       break;
432     case KeyboardEnableFlag::kExtensionEnabled:
433       keyboard_enable_flags_.erase(KeyboardEnableFlag::kExtensionDisabled);
434       break;
435     case KeyboardEnableFlag::kExtensionDisabled:
436       keyboard_enable_flags_.erase(KeyboardEnableFlag::kExtensionEnabled);
437       break;
438     default:
439       break;
440   }
441 
442   EnableFlagsChanged();
443 
444   UpdateKeyboardAsRequestedBy(flag);
445 }
446 
ClearEnableFlag(KeyboardEnableFlag flag)447 void KeyboardUIController::ClearEnableFlag(KeyboardEnableFlag flag) {
448   if (!IsEnableFlagSet(flag))
449     return;
450 
451   keyboard_enable_flags_.erase(flag);
452   EnableFlagsChanged();
453 
454   UpdateKeyboardAsRequestedBy(flag);
455 }
456 
IsEnableFlagSet(KeyboardEnableFlag flag) const457 bool KeyboardUIController::IsEnableFlagSet(KeyboardEnableFlag flag) const {
458   return base::Contains(keyboard_enable_flags_, flag);
459 }
460 
IsKeyboardEnableRequested() const461 bool KeyboardUIController::IsKeyboardEnableRequested() const {
462   // Accessibility setting prioritized over policy/arc overrides.
463   if (IsEnableFlagSet(KeyboardEnableFlag::kAccessibilityEnabled))
464     return true;
465 
466   // Keyboard can be enabled temporarily by the shelf.
467   if (IsEnableFlagSet(KeyboardEnableFlag::kShelfEnabled))
468     return true;
469 
470   if (IsEnableFlagSet(KeyboardEnableFlag::kAndroidDisabled) ||
471       IsEnableFlagSet(KeyboardEnableFlag::kPolicyDisabled)) {
472     return false;
473   }
474   if (IsEnableFlagSet(KeyboardEnableFlag::kPolicyEnabled))
475     return true;
476 
477   // Command line overrides extension and touch enabled flags.
478   if (IsEnableFlagSet(KeyboardEnableFlag::kCommandLineEnabled))
479     return true;
480 
481   if (IsEnableFlagSet(KeyboardEnableFlag::kExtensionDisabled))
482     return false;
483 
484   return IsEnableFlagSet(KeyboardEnableFlag::kExtensionEnabled) ||
485          IsEnableFlagSet(KeyboardEnableFlag::kTouchEnabled);
486 }
487 
UpdateKeyboardAsRequestedBy(KeyboardEnableFlag flag)488 void KeyboardUIController::UpdateKeyboardAsRequestedBy(
489     KeyboardEnableFlag flag) {
490   if (IsKeyboardEnableRequested()) {
491     // Note that there are two versions of the on-screen keyboard. A full layout
492     // is provided for accessibility, which includes sticky modifier keys to
493     // enable typing of hotkeys. A compact version is used in tablet mode to
494     // provide a layout with larger keys to facilitate touch typing. In the
495     // event that the a11y keyboard is being disabled, an on-screen keyboard
496     // might still be enabled and a forced reset is required to pick up the
497     // layout change.
498     if (IsEnabled() && flag == KeyboardEnableFlag::kAccessibilityEnabled)
499       RebuildKeyboardIfEnabled();
500     else
501       EnableKeyboard();
502   } else {
503     DisableKeyboard();
504   }
505 }
506 
IsKeyboardOverscrollEnabled() const507 bool KeyboardUIController::IsKeyboardOverscrollEnabled() const {
508   if (!IsEnabled())
509     return false;
510 
511   // Users of the sticky accessibility on-screen keyboard are likely to be using
512   // mouse input, which may interfere with overscrolling.
513   if (IsEnabled() && !IsOverscrollAllowed())
514     return false;
515 
516   // If overscroll enabled behavior is set, use it instead. Currently
517   // login / out-of-box disable keyboard overscroll. http://crbug.com/363635
518   if (keyboard_config_.overscroll_behavior !=
519       KeyboardOverscrollBehavior::kDefault) {
520     return keyboard_config_.overscroll_behavior ==
521            KeyboardOverscrollBehavior::kEnabled;
522   }
523 
524   return true;
525 }
526 
527 // private
HideKeyboard(HideReason reason)528 void KeyboardUIController::HideKeyboard(HideReason reason) {
529   TRACE_EVENT0("vk", "HideKeyboard");
530 
531   // Decide whether regaining focus in a web-based text field should cause
532   // the keyboard to come back.
533   switch (reason) {
534     case HIDE_REASON_SYSTEM_IMPLICIT:
535       time_of_last_blur_ = base::Time::Now();
536       break;
537 
538     case HIDE_REASON_SYSTEM_TEMPORARY:
539     case HIDE_REASON_SYSTEM_EXPLICIT:
540     case HIDE_REASON_USER_EXPLICIT:
541     case HIDE_REASON_USER_IMPLICIT:
542       time_of_last_blur_ = base::Time::UnixEpoch();
543       break;
544   }
545 
546   switch (model_.state()) {
547     case KeyboardUIState::kUnknown:
548     case KeyboardUIState::kInitial:
549     case KeyboardUIState::kHidden:
550       return;
551     case KeyboardUIState::kLoading:
552       show_on_keyboard_window_load_ = false;
553       return;
554 
555     case KeyboardUIState::kWillHide:
556     case KeyboardUIState::kShown: {
557       SetTouchEventLogging(true /* enable */);
558 
559       // Log whether this was a user or system (automatic) action.
560       switch (reason) {
561         case HIDE_REASON_SYSTEM_EXPLICIT:
562         case HIDE_REASON_SYSTEM_IMPLICIT:
563         case HIDE_REASON_SYSTEM_TEMPORARY:
564           LogKeyboardControlEvent(KeyboardControlEvent::kHideAuto);
565           break;
566         case HIDE_REASON_USER_EXPLICIT:
567         case HIDE_REASON_USER_IMPLICIT:
568           LogKeyboardControlEvent(KeyboardControlEvent::kHideUser);
569           break;
570       }
571 
572       NotifyKeyboardBoundsChanging(gfx::Rect());
573 
574       set_keyboard_locked(false);
575 
576       aura::Window* window = GetKeyboardWindow();
577       DCHECK(window);
578 
579       animation_observer_ = std::make_unique<CallbackAnimationObserver>(
580           base::BindOnce(&KeyboardUIController::HideAnimationFinished,
581                          base::Unretained(this)));
582       ui::ScopedLayerAnimationSettings layer_animation_settings(
583           window->layer()->GetAnimator());
584       layer_animation_settings.AddObserver(animation_observer_.get());
585 
586       {
587         // Scoped settings go into effect when scope ends.
588         ::wm::ScopedHidingAnimationSettings hiding_settings(window);
589         container_behavior_->DoHidingAnimation(window, &hiding_settings);
590       }
591 
592       ui_->HideKeyboardWindow();
593       ChangeState(KeyboardUIState::kHidden);
594 
595       for (auto& observer : observer_list_)
596         observer.OnKeyboardHidden(reason == HIDE_REASON_SYSTEM_TEMPORARY);
597 
598       break;
599     }
600   }
601 }
602 
HideKeyboardByUser()603 void KeyboardUIController::HideKeyboardByUser() {
604   HideKeyboard(HIDE_REASON_USER_EXPLICIT);
605 }
606 
HideKeyboardImplicitlyByUser()607 void KeyboardUIController::HideKeyboardImplicitlyByUser() {
608   if (!keyboard_locked_)
609     HideKeyboard(HIDE_REASON_USER_IMPLICIT);
610 }
611 
HideKeyboardTemporarilyForTransition()612 void KeyboardUIController::HideKeyboardTemporarilyForTransition() {
613   HideKeyboard(HIDE_REASON_SYSTEM_TEMPORARY);
614 }
615 
HideKeyboardExplicitlyBySystem()616 void KeyboardUIController::HideKeyboardExplicitlyBySystem() {
617   HideKeyboard(HIDE_REASON_SYSTEM_EXPLICIT);
618 }
619 
HideKeyboardImplicitlyBySystem()620 void KeyboardUIController::HideKeyboardImplicitlyBySystem() {
621   if (model_.state() != KeyboardUIState::kShown || keyboard_locked_)
622     return;
623 
624   ChangeState(KeyboardUIState::kWillHide);
625 
626   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
627       FROM_HERE,
628       base::BindOnce(&KeyboardUIController::HideKeyboard,
629                      weak_factory_will_hide_.GetWeakPtr(),
630                      HIDE_REASON_SYSTEM_IMPLICIT),
631       kHideKeyboardDelay);
632 }
633 
634 // private
HideAnimationFinished()635 void KeyboardUIController::HideAnimationFinished() {
636   if (model_.state() == KeyboardUIState::kHidden) {
637     if (queued_container_type_) {
638       SetContainerBehaviorInternal(queued_container_type_->container_type());
639       // The position of the container window will be adjusted shortly in
640       // |PopulateKeyboardContent| before showing animation, so we can set the
641       // passed bounds directly.
642       SetKeyboardWindowBounds(queued_container_type_->target_bounds());
643       ShowKeyboard(false /* lock */);
644     }
645 
646     if (queued_display_change_) {
647       ShowKeyboardInDisplay(queued_display_change_->new_display());
648       SetKeyboardWindowBounds(queued_display_change_->new_bounds_in_local());
649       queued_display_change_ = nullptr;
650     }
651   }
652 }
653 
654 // private
ShowAnimationFinished()655 void KeyboardUIController::ShowAnimationFinished() {
656   MarkKeyboardLoadFinished();
657 
658   // Notify observers after animation finished to prevent reveal desktop
659   // background during animation.
660   // If the current state is not SHOWN, it means the state was changed after the
661   // animation started. Do not tell the observers the stale bounds.
662   if (model_.state() == KeyboardUIState::kShown)
663     NotifyKeyboardBoundsChanging(GetKeyboardWindow()->GetBoundsInRootWindow());
664 }
665 
666 // private
SetContainerBehaviorInternal(ContainerType type)667 void KeyboardUIController::SetContainerBehaviorInternal(ContainerType type) {
668   // Reset the hit test event targeter because the hit test bounds will
669   // be wrong when container type changes and may cause the UI to be unusable.
670   if (GetKeyboardWindow())
671     GetKeyboardWindow()->SetEventTargeter(nullptr);
672 
673   switch (type) {
674     case ContainerType::kFullWidth:
675       container_behavior_ = std::make_unique<ContainerFullWidthBehavior>(this);
676       break;
677     case ContainerType::kFloating:
678       container_behavior_ = std::make_unique<ContainerFloatingBehavior>(this);
679       break;
680   }
681 }
682 
ShowKeyboard(bool lock)683 void KeyboardUIController::ShowKeyboard(bool lock) {
684   DVLOG(1) << "ShowKeyboard";
685   set_keyboard_locked(lock);
686   ShowKeyboardInternal(layout_delegate_->GetContainerForDefaultDisplay());
687 }
688 
ShowKeyboardInDisplay(const display::Display & display)689 void KeyboardUIController::ShowKeyboardInDisplay(
690     const display::Display& display) {
691   DVLOG(1) << "ShowKeyboardInDisplay: " << display.id();
692   set_keyboard_locked(true);
693   ShowKeyboardInternal(layout_delegate_->GetContainerForDisplay(display));
694 }
695 
GetVisualBoundsInScreen() const696 gfx::Rect KeyboardUIController::GetVisualBoundsInScreen() const {
697   gfx::Rect visual_bounds_in_screen = visual_bounds_in_root_;
698   ::wm::ConvertRectToScreen(GetRootWindow(), &visual_bounds_in_screen);
699   return visual_bounds_in_screen;
700 }
701 
LoadKeyboardWindowInBackground()702 void KeyboardUIController::LoadKeyboardWindowInBackground() {
703   DCHECK_EQ(model_.state(), KeyboardUIState::kInitial);
704 
705   TRACE_EVENT0("vk", "LoadKeyboardWindowInBackground");
706 
707   // For now, using Unretained is safe here because the |ui_| is owned by
708   // |this| and the callback does not outlive |ui_|.
709   // TODO(https://crbug.com/845780): Use a weak ptr here in case this
710   // assumption changes.
711   DVLOG(1) << "LoadKeyboardWindow";
712   aura::Window* keyboard_window = ui_->LoadKeyboardWindow(
713       base::BindOnce(&KeyboardUIController::NotifyKeyboardWindowLoaded,
714                      base::Unretained(this)));
715   keyboard_window->AddPreTargetHandler(&event_handler_);
716   keyboard_window->AddObserver(this);
717   parent_container_->AddChild(keyboard_window);
718 
719   ChangeState(KeyboardUIState::kLoading);
720 }
721 
GetInputMethodForTest()722 ui::InputMethod* KeyboardUIController::GetInputMethodForTest() {
723   return ui_->GetInputMethod();
724 }
725 
EnsureCaretInWorkAreaForTest(const gfx::Rect & occluded_bounds_in_screen)726 void KeyboardUIController::EnsureCaretInWorkAreaForTest(
727     const gfx::Rect& occluded_bounds_in_screen) {
728   EnsureCaretInWorkArea(occluded_bounds_in_screen);
729 }
730 
731 // ContainerBehavior::Delegate overrides
732 
IsKeyboardLocked() const733 bool KeyboardUIController::IsKeyboardLocked() const {
734   return keyboard_locked_;
735 }
736 
GetBoundsInScreen() const737 gfx::Rect KeyboardUIController::GetBoundsInScreen() const {
738   return GetKeyboardWindow()->GetBoundsInScreen();
739 }
740 
MoveKeyboardWindow(const gfx::Rect & new_bounds)741 void KeyboardUIController::MoveKeyboardWindow(const gfx::Rect& new_bounds) {
742   DCHECK(IsKeyboardVisible());
743   SetKeyboardWindowBounds(new_bounds);
744 }
745 
MoveKeyboardWindowToDisplay(const display::Display & display,const gfx::Rect & new_bounds_in_root)746 void KeyboardUIController::MoveKeyboardWindowToDisplay(
747     const display::Display& display,
748     const gfx::Rect& new_bounds_in_root) {
749   queued_display_change_ =
750       std::make_unique<QueuedDisplayChange>(display, new_bounds_in_root);
751   HideKeyboardTemporarilyForTransition();
752 }
753 
TransferGestureEventToShelf(const ui::GestureEvent & e)754 void KeyboardUIController::TransferGestureEventToShelf(
755     const ui::GestureEvent& e) {
756   layout_delegate_->TransferGestureEventToShelf(e);
757 }
758 
759 // aura::WindowObserver overrides
760 
OnWindowAddedToRootWindow(aura::Window * window)761 void KeyboardUIController::OnWindowAddedToRootWindow(aura::Window* window) {
762   container_behavior_->SetCanonicalBounds(GetKeyboardWindow(),
763                                           GetRootWindow()->bounds());
764 }
765 
OnWindowBoundsChanged(aura::Window * window,const gfx::Rect & old_bounds_in_root,const gfx::Rect & new_bounds_in_root,ui::PropertyChangeReason reason)766 void KeyboardUIController::OnWindowBoundsChanged(
767     aura::Window* window,
768     const gfx::Rect& old_bounds_in_root,
769     const gfx::Rect& new_bounds_in_root,
770     ui::PropertyChangeReason reason) {
771   if (!GetKeyboardWindow())
772     return;
773 
774   // |window| could be the root window (for detecting screen rotations) or the
775   // keyboard window (for detecting keyboard bounds changes).
776   if (window == GetRootWindow())
777     container_behavior_->SetCanonicalBounds(GetKeyboardWindow(),
778                                             new_bounds_in_root);
779   else if (window == GetKeyboardWindow())
780     NotifyKeyboardBoundsChanging(new_bounds_in_root);
781 }
782 
783 // InputMethodObserver overrides
784 
OnInputMethodDestroyed(const ui::InputMethod * input_method)785 void KeyboardUIController::OnInputMethodDestroyed(
786     const ui::InputMethod* input_method) {
787   ime_observer_.RemoveAll();
788   OnTextInputStateChanged(nullptr);
789 }
790 
OnTextInputStateChanged(const ui::TextInputClient * client)791 void KeyboardUIController::OnTextInputStateChanged(
792     const ui::TextInputClient* client) {
793   TRACE_EVENT0("vk", "OnTextInputStateChanged");
794 
795   bool focused =
796       client && (client->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE &&
797                  client->GetTextInputMode() != ui::TEXT_INPUT_MODE_NONE);
798   bool should_hide = !focused && container_behavior_->TextBlurHidesKeyboard();
799   bool is_web =
800       client && client->GetTextInputFlags() != ui::TEXT_INPUT_FLAG_NONE;
801 
802   if (should_hide) {
803     switch (model_.state()) {
804       case KeyboardUIState::kLoading:
805         show_on_keyboard_window_load_ = false;
806         return;
807       case KeyboardUIState::kShown:
808         HideKeyboardImplicitlyBySystem();
809         return;
810       default:
811         return;
812     }
813   } else {
814     switch (model_.state()) {
815       case KeyboardUIState::kWillHide:
816         // Abort a pending keyboard hide.
817         ChangeState(KeyboardUIState::kShown);
818         return;
819       case KeyboardUIState::kHidden:
820         if (focused && is_web)
821           ShowKeyboardIfWithinTransientBlurThreshold();
822         return;
823       default:
824         break;
825     }
826     // Do not explicitly show the Virtual keyboard unless it is in the process
827     // of hiding or the hide duration was very short (transient blur). Instead,
828     // the virtual keyboard is shown in response to a user gesture (mouse or
829     // touch) that is received while an element has input focus. Showing the
830     // keyboard requires an explicit call to OnShowVirtualKeyboardIfEnabled.
831   }
832 }
833 
ShowKeyboardIfWithinTransientBlurThreshold()834 void KeyboardUIController::ShowKeyboardIfWithinTransientBlurThreshold() {
835   if (base::Time::Now() - time_of_last_blur_ < kTransientBlurThreshold)
836     ShowKeyboard(false);
837 }
838 
OnShowVirtualKeyboardIfEnabled()839 void KeyboardUIController::OnShowVirtualKeyboardIfEnabled() {
840   DVLOG(1) << "OnShowVirtualKeyboardIfEnabled: " << IsEnabled();
841   // Calling |ShowKeyboardInternal| may move the keyboard to another display.
842   if (IsEnabled() && !keyboard_locked_)
843     ShowKeyboardInternal(layout_delegate_->GetContainerForDefaultDisplay());
844 }
845 
ShowKeyboardInternal(aura::Window * target_container)846 void KeyboardUIController::ShowKeyboardInternal(
847     aura::Window* target_container) {
848   MarkKeyboardLoadStarted();
849   PopulateKeyboardContent(target_container);
850   UpdateInputMethodObserver();
851 }
852 
PopulateKeyboardContent(aura::Window * target_container)853 void KeyboardUIController::PopulateKeyboardContent(
854     aura::Window* target_container) {
855   DCHECK_NE(model_.state(), KeyboardUIState::kInitial);
856 
857   DVLOG(1) << "PopulateKeyboardContent: " << StateToStr(model_.state());
858   TRACE_EVENT0("vk", "PopulateKeyboardContent");
859 
860   MoveToParentContainer(target_container);
861 
862   aura::Window* keyboard_window = GetKeyboardWindow();
863   DCHECK(keyboard_window);
864   DCHECK_EQ(parent_container_, keyboard_window->parent());
865 
866   switch (model_.state()) {
867     case KeyboardUIState::kShown:
868       return;
869     case KeyboardUIState::kLoading:
870       show_on_keyboard_window_load_ = true;
871       return;
872     default:
873       break;
874   }
875 
876   ui_->ReloadKeyboardIfNeeded();
877 
878   SetTouchEventLogging(false /* enable */);
879 
880   switch (model_.state()) {
881     case KeyboardUIState::kWillHide:
882       ChangeState(KeyboardUIState::kShown);
883       return;
884     default:
885       break;
886   }
887 
888   DCHECK_EQ(model_.state(), KeyboardUIState::kHidden);
889 
890   // If the container is not animating, makes sure the position and opacity
891   // are at begin states for animation.
892   container_behavior_->InitializeShowAnimationStartingState(keyboard_window);
893 
894   LogKeyboardControlEvent(KeyboardControlEvent::kShow);
895   RecordUkmKeyboardShown();
896 
897   ui::LayerAnimator* container_animator =
898       keyboard_window->layer()->GetAnimator();
899   container_animator->set_preemption_strategy(
900       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
901 
902   ui_->ShowKeyboardWindow();
903 
904   animation_observer_ = std::make_unique<CallbackAnimationObserver>(
905       base::BindOnce(&KeyboardUIController::ShowAnimationFinished,
906                      base::Unretained(this)));
907   ui::ScopedLayerAnimationSettings settings(container_animator);
908   settings.AddObserver(animation_observer_.get());
909 
910   container_behavior_->DoShowingAnimation(keyboard_window, &settings);
911 
912   // the queued container behavior will notify JS to change layout when it
913   // gets destroyed.
914   queued_container_type_ = nullptr;
915 
916   ChangeState(KeyboardUIState::kShown);
917 
918   UMA_HISTOGRAM_ENUMERATION("InputMethod.VirtualKeyboard.ContainerBehavior",
919                             GetActiveContainerType());
920 }
921 
WillHideKeyboard() const922 bool KeyboardUIController::WillHideKeyboard() const {
923   bool res = weak_factory_will_hide_.HasWeakPtrs();
924   DCHECK_EQ(res, model_.state() == KeyboardUIState::kWillHide);
925   return res;
926 }
927 
NotifyKeyboardConfigChanged()928 void KeyboardUIController::NotifyKeyboardConfigChanged() {
929   for (auto& observer : observer_list_)
930     observer.OnKeyboardConfigChanged(keyboard_config_);
931 }
932 
ChangeState(KeyboardUIState state)933 void KeyboardUIController::ChangeState(KeyboardUIState state) {
934   model_.ChangeState(state);
935 
936   if (state != KeyboardUIState::kWillHide)
937     weak_factory_will_hide_.InvalidateWeakPtrs();
938   if (state != KeyboardUIState::kLoading)
939     show_on_keyboard_window_load_ = false;
940 
941   weak_factory_report_lingering_state_.InvalidateWeakPtrs();
942   switch (model_.state()) {
943     case KeyboardUIState::kLoading:
944     case KeyboardUIState::kWillHide:
945       base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
946           FROM_HERE,
947           base::BindOnce(&KeyboardUIController::ReportLingeringState,
948                          weak_factory_report_lingering_state_.GetWeakPtr()),
949           kReportLingeringStateDelay);
950       break;
951     default:
952       // Do nothing
953       break;
954   }
955 }
956 
ReportLingeringState()957 void KeyboardUIController::ReportLingeringState() {
958   LOG(ERROR) << "KeyboardUIController lingering in "
959              << StateToStr(model_.state());
960   UMA_HISTOGRAM_ENUMERATION("VirtualKeyboard.LingeringIntermediateState",
961                             model_.state());
962 }
963 
GetWorkspaceOccludedBoundsInScreen() const964 gfx::Rect KeyboardUIController::GetWorkspaceOccludedBoundsInScreen() const {
965   if (!ui_)
966     return gfx::Rect();
967 
968   const gfx::Rect visual_bounds_in_window(visual_bounds_in_root_.size());
969 
970   gfx::Rect occluded_bounds_in_screen =
971       container_behavior_->GetOccludedBounds(visual_bounds_in_window);
972   ::wm::ConvertRectToScreen(GetKeyboardWindow(), &occluded_bounds_in_screen);
973 
974   return occluded_bounds_in_screen;
975 }
976 
GetKeyboardLockScreenOffsetBounds() const977 gfx::Rect KeyboardUIController::GetKeyboardLockScreenOffsetBounds() const {
978   // Overscroll is generally dependent on lock state, however, its behavior
979   // temporarily overridden by a static field in certain lock screen contexts.
980   // Furthermore, floating keyboard should never affect layout.
981   if (!IsKeyboardOverscrollEnabled() &&
982       container_behavior_->GetType() != ContainerType::kFloating) {
983     return visual_bounds_in_root_;
984   }
985   return gfx::Rect();
986 }
987 
SetOccludedBounds(const gfx::Rect & bounds_in_window)988 void KeyboardUIController::SetOccludedBounds(
989     const gfx::Rect& bounds_in_window) {
990   container_behavior_->SetOccludedBounds(bounds_in_window);
991 
992   // Notify that only the occluded bounds have changed.
993   if (IsKeyboardVisible())
994     NotifyKeyboardBoundsChanging(visual_bounds_in_root_);
995 }
996 
SetHitTestBounds(const std::vector<gfx::Rect> & bounds_in_window)997 void KeyboardUIController::SetHitTestBounds(
998     const std::vector<gfx::Rect>& bounds_in_window) {
999   if (!GetKeyboardWindow())
1000     return;
1001 
1002   GetKeyboardWindow()->SetEventTargeter(
1003       std::make_unique<ShapedWindowTargeter>(bounds_in_window));
1004 }
1005 
SetAreaToRemainOnScreen(const gfx::Rect & bounds_in_window)1006 bool KeyboardUIController::SetAreaToRemainOnScreen(
1007     const gfx::Rect& bounds_in_window) {
1008   gfx::Rect window_bounds_in_screen = GetKeyboardWindow()->GetBoundsInScreen();
1009   gfx::Rect bounds_in_screen =
1010       gfx::Rect(window_bounds_in_screen.x() + bounds_in_window.x(),
1011                 window_bounds_in_screen.y() + bounds_in_window.y(),
1012                 bounds_in_window.width(), bounds_in_window.height());
1013 
1014   if (!window_bounds_in_screen.Contains(bounds_in_screen))
1015     return false;
1016 
1017   container_behavior_->SetAreaToRemainOnScreen(bounds_in_window);
1018   return true;
1019 }
1020 
SetKeyboardWindowBoundsInScreen(const gfx::Rect & bounds_in_screen)1021 bool KeyboardUIController::SetKeyboardWindowBoundsInScreen(
1022     const gfx::Rect& bounds_in_screen) {
1023   const display::Display& current_display =
1024       display_util_.GetNearestDisplayToWindow(GetRootWindow());
1025 
1026   gfx::Rect display_bounds = current_display.bounds();
1027   if (bounds_in_screen.width() > display_bounds.width() ||
1028       bounds_in_screen.height() > display_bounds.height()) {
1029     return false;
1030   }
1031 
1032   gfx::Rect constrained_bounds_in_screen =
1033       AdjustSetBoundsRequest(current_display.bounds(), bounds_in_screen);
1034 
1035   GetKeyboardWindow()->SetBoundsInScreen(constrained_bounds_in_screen,
1036                                          current_display);
1037   return true;
1038 }
1039 
AdjustSetBoundsRequest(const gfx::Rect & display_bounds,const gfx::Rect & requested_bounds_in_screen) const1040 gfx::Rect KeyboardUIController::AdjustSetBoundsRequest(
1041     const gfx::Rect& display_bounds,
1042     const gfx::Rect& requested_bounds_in_screen) const {
1043   return container_behavior_->AdjustSetBoundsRequest(
1044       display_bounds, requested_bounds_in_screen);
1045 }
1046 
IsOverscrollAllowed() const1047 bool KeyboardUIController::IsOverscrollAllowed() const {
1048   return container_behavior_->IsOverscrollAllowed();
1049 }
1050 
HandlePointerEvent(const ui::LocatedEvent & event)1051 bool KeyboardUIController::HandlePointerEvent(const ui::LocatedEvent& event) {
1052   const display::Display& current_display =
1053       display_util_.GetNearestDisplayToWindow(GetRootWindow());
1054   return container_behavior_->HandlePointerEvent(event, current_display);
1055 }
1056 
HandleGestureEvent(const ui::GestureEvent & event)1057 bool KeyboardUIController::HandleGestureEvent(const ui::GestureEvent& event) {
1058   return container_behavior_->HandleGestureEvent(event, GetBoundsInScreen());
1059 }
1060 
SetContainerType(ContainerType type,const gfx::Rect & target_bounds_in_root,base::OnceCallback<void (bool)> callback)1061 void KeyboardUIController::SetContainerType(
1062     ContainerType type,
1063     const gfx::Rect& target_bounds_in_root,
1064     base::OnceCallback<void(bool)> callback) {
1065   if (container_behavior_->GetType() == type) {
1066     std::move(callback).Run(false);
1067     return;
1068   }
1069 
1070   if (model_.state() == KeyboardUIState::kShown) {
1071     // Keyboard is already shown. Hiding the keyboard at first then switching
1072     // container type.
1073     queued_container_type_ = std::make_unique<QueuedContainerType>(
1074         this, type, target_bounds_in_root, std::move(callback));
1075     HideKeyboard(HIDE_REASON_SYSTEM_TEMPORARY);
1076   } else {
1077     // Keyboard is hidden. Switching the container type immediately and invoking
1078     // the passed callback now.
1079     SetContainerBehaviorInternal(type);
1080     SetKeyboardWindowBounds(target_bounds_in_root);
1081     DCHECK_EQ(GetActiveContainerType(), type);
1082     std::move(callback).Run(true /* change_successful */);
1083   }
1084 }
1085 
RecordUkmKeyboardShown()1086 void KeyboardUIController::RecordUkmKeyboardShown() {
1087   ui::TextInputClient* text_input_client = GetTextInputClient();
1088   if (!text_input_client)
1089     return;
1090 
1091   keyboard::RecordUkmKeyboardShown(
1092       text_input_client->GetClientSourceForMetrics(),
1093       text_input_client->GetTextInputType());
1094 }
1095 
SetDraggableArea(const gfx::Rect & rect)1096 void KeyboardUIController::SetDraggableArea(const gfx::Rect& rect) {
1097   container_behavior_->SetDraggableArea(rect);
1098 }
1099 
IsKeyboardVisible()1100 bool KeyboardUIController::IsKeyboardVisible() {
1101   if (model_.state() == KeyboardUIState::kShown) {
1102     DCHECK(IsEnabled());
1103     return true;
1104   }
1105   return false;
1106 }
1107 
GetTextInputClient()1108 ui::TextInputClient* KeyboardUIController::GetTextInputClient() {
1109   return ui_->GetInputMethod()->GetTextInputClient();
1110 }
1111 
UpdateInputMethodObserver()1112 void KeyboardUIController::UpdateInputMethodObserver() {
1113   ui::InputMethod* ime = ui_->GetInputMethod();
1114 
1115   // IME could be null during initialization. Ignoring the case is okay because
1116   // UpdateInputMethodObserver() will be called later on.
1117   if (!ime)
1118     return;
1119 
1120   if (ime_observer_.IsObserving(ime))
1121     return;
1122 
1123   // Only observes the current active IME.
1124   ime_observer_.RemoveAll();
1125   ime_observer_.Add(ime);
1126 
1127   // Note: We used to call OnTextInputStateChanged(ime->GetTextInputClient())
1128   // here, but that can trigger HideKeyboardImplicitlyBySystem() from a call to
1129   // ShowKeyboard() when using mojo APIs in Chrome (SingleProcessMash) if
1130   // ime->GetTextInputClient() isn't focused.
1131 }
1132 
EnsureCaretInWorkArea(const gfx::Rect & occluded_bounds_in_screen)1133 void KeyboardUIController::EnsureCaretInWorkArea(
1134     const gfx::Rect& occluded_bounds_in_screen) {
1135   ui::InputMethod* ime = ui_->GetInputMethod();
1136   if (!ime)
1137     return;
1138 
1139   TRACE_EVENT0("vk", "EnsureCaretInWorkArea");
1140 
1141   if (IsOverscrollAllowed()) {
1142     ime->SetOnScreenKeyboardBounds(occluded_bounds_in_screen);
1143   } else if (ime->GetTextInputClient()) {
1144     ime->GetTextInputClient()->EnsureCaretNotInRect(occluded_bounds_in_screen);
1145   }
1146 }
1147 
MarkKeyboardLoadStarted()1148 void KeyboardUIController::MarkKeyboardLoadStarted() {
1149   if (!keyboard_load_time_logged_)
1150     keyboard_load_time_start_ = base::Time::Now();
1151 }
1152 
MarkKeyboardLoadFinished()1153 void KeyboardUIController::MarkKeyboardLoadFinished() {
1154   // Possible to get a load finished without a start if navigating directly to
1155   // chrome://keyboard.
1156   if (keyboard_load_time_start_.is_null())
1157     return;
1158 
1159   if (keyboard_load_time_logged_)
1160     return;
1161 
1162   // Log the delta only once.
1163   UMA_HISTOGRAM_TIMES("VirtualKeyboard.InitLatency.FirstLoad",
1164                       base::Time::Now() - keyboard_load_time_start_);
1165   keyboard_load_time_logged_ = true;
1166 }
1167 
EnableFlagsChanged()1168 void KeyboardUIController::EnableFlagsChanged() {
1169   for (auto& observer : observer_list_)
1170     observer.OnKeyboardEnableFlagsChanged(keyboard_enable_flags_);
1171 }
1172 
1173 }  // namespace keyboard
1174