keyboard_ui_controller.cc 38 KB

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