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 "ui/keyboard/keyboard_controller.h"
6
7#include <set>
8
9#include "base/bind.h"
10#include "base/command_line.h"
11#include "content/public/browser/render_widget_host.h"
12#include "content/public/browser/render_widget_host_iterator.h"
13#include "content/public/browser/render_widget_host_view.h"
14#include "ui/aura/window.h"
15#include "ui/aura/window_delegate.h"
16#include "ui/aura/window_observer.h"
17#include "ui/base/cursor/cursor.h"
18#include "ui/base/hit_test.h"
19#include "ui/base/ime/input_method.h"
20#include "ui/base/ime/text_input_client.h"
21#include "ui/compositor/layer_animation_observer.h"
22#include "ui/compositor/scoped_layer_animation_settings.h"
23#include "ui/gfx/path.h"
24#include "ui/gfx/rect.h"
25#include "ui/gfx/skia_util.h"
26#include "ui/keyboard/keyboard_controller_observer.h"
27#include "ui/keyboard/keyboard_controller_proxy.h"
28#include "ui/keyboard/keyboard_layout_manager.h"
29#include "ui/keyboard/keyboard_util.h"
30#include "ui/wm/core/masked_window_targeter.h"
31
32#if defined(OS_CHROMEOS)
33#include "base/process/launch.h"
34#include "base/sys_info.h"
35#endif
36
37namespace {
38
39const int kHideKeyboardDelayMs = 100;
40
41// The virtual keyboard show/hide animation duration.
42const int kShowAnimationDurationMs = 350;
43const int kHideAnimationDurationMs = 100;
44
45// The opacity of virtual keyboard container when show animation starts or
46// hide animation finishes.
47// TODO(rsadam@): Investigate why setting this to zero crashes.
48const float kAnimationStartOrAfterHideOpacity = 0.01f;
49
50// Event targeter for the keyboard container.
51class KeyboardContainerTargeter : public wm::MaskedWindowTargeter {
52 public:
53  KeyboardContainerTargeter(aura::Window* container,
54                            keyboard::KeyboardControllerProxy* proxy)
55      : wm::MaskedWindowTargeter(container),
56        proxy_(proxy) {
57  }
58
59  virtual ~KeyboardContainerTargeter() {}
60
61 private:
62  // wm::MaskedWindowTargeter:
63  virtual bool GetHitTestMask(aura::Window* window,
64                              gfx::Path* mask) const OVERRIDE {
65    if (proxy_ && !proxy_->HasKeyboardWindow())
66      return true;
67    gfx::Rect keyboard_bounds = proxy_ ? proxy_->GetKeyboardWindow()->bounds() :
68        keyboard::DefaultKeyboardBoundsFromWindowBounds(window->bounds());
69    mask->addRect(RectToSkRect(keyboard_bounds));
70    return true;
71  }
72
73  keyboard::KeyboardControllerProxy* proxy_;
74
75  DISALLOW_COPY_AND_ASSIGN(KeyboardContainerTargeter);
76};
77
78// The KeyboardWindowDelegate makes sure the keyboard-window does not get focus.
79// This is necessary to make sure that the synthetic key-events reach the target
80// window.
81// The delegate deletes itself when the window is destroyed.
82class KeyboardWindowDelegate : public aura::WindowDelegate {
83 public:
84  explicit KeyboardWindowDelegate(keyboard::KeyboardControllerProxy* proxy)
85      : proxy_(proxy) {}
86  virtual ~KeyboardWindowDelegate() {}
87
88 private:
89  // Overridden from aura::WindowDelegate:
90  virtual gfx::Size GetMinimumSize() const OVERRIDE { return gfx::Size(); }
91  virtual gfx::Size GetMaximumSize() const OVERRIDE { return gfx::Size(); }
92  virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
93                               const gfx::Rect& new_bounds) OVERRIDE {
94    bounds_ = new_bounds;
95  }
96  virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE {
97    return gfx::kNullCursor;
98  }
99  virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE {
100    return HTNOWHERE;
101  }
102  virtual bool ShouldDescendIntoChildForEventHandling(
103      aura::Window* child,
104      const gfx::Point& location) OVERRIDE {
105    return true;
106  }
107  virtual bool CanFocus() OVERRIDE { return false; }
108  virtual void OnCaptureLost() OVERRIDE {}
109  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {}
110  virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
111  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {}
112  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { delete this; }
113  virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {}
114  virtual bool HasHitTestMask() const OVERRIDE {
115    return !proxy_ || proxy_->HasKeyboardWindow();
116  }
117  virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {
118    if (proxy_ && !proxy_->HasKeyboardWindow())
119      return;
120    gfx::Rect keyboard_bounds = proxy_ ? proxy_->GetKeyboardWindow()->bounds() :
121        keyboard::DefaultKeyboardBoundsFromWindowBounds(bounds_);
122    mask->addRect(RectToSkRect(keyboard_bounds));
123  }
124
125  gfx::Rect bounds_;
126  keyboard::KeyboardControllerProxy* proxy_;
127
128  DISALLOW_COPY_AND_ASSIGN(KeyboardWindowDelegate);
129};
130
131void ToggleTouchEventLogging(bool enable) {
132#if defined(OS_CHROMEOS)
133  if (!base::SysInfo::IsRunningOnChromeOS())
134    return;
135  CommandLine command(
136      base::FilePath("/opt/google/touchscreen/toggle_touch_event_logging"));
137  if (enable)
138    command.AppendArg("1");
139  else
140    command.AppendArg("0");
141  VLOG(1) << "Running " << command.GetCommandLineString();
142  base::LaunchOptions options;
143  options.wait = true;
144  base::LaunchProcess(command, options, NULL);
145#endif
146}
147
148aura::Window *GetFrameWindow(aura::Window *window) {
149  // Each container window has a non-negative id.  Stop traversing at the child
150  // of a container window.
151  if (!window)
152    return NULL;
153  while (window->parent() && window->parent()->id() < 0) {
154    window = window->parent();
155  }
156  return window;
157}
158
159}  // namespace
160
161namespace keyboard {
162
163// Observer for both keyboard show and hide animations. It should be owned by
164// KeyboardController.
165class CallbackAnimationObserver : public ui::LayerAnimationObserver {
166 public:
167  CallbackAnimationObserver(ui::LayerAnimator* animator,
168                            base::Callback<void(void)> callback);
169  virtual ~CallbackAnimationObserver();
170
171 private:
172  // Overridden from ui::LayerAnimationObserver:
173  virtual void OnLayerAnimationEnded(ui::LayerAnimationSequence* seq) OVERRIDE;
174  virtual void OnLayerAnimationAborted(
175      ui::LayerAnimationSequence* seq) OVERRIDE;
176  virtual void OnLayerAnimationScheduled(
177      ui::LayerAnimationSequence* seq) OVERRIDE {}
178
179  ui::LayerAnimator* animator_;
180  base::Callback<void(void)> callback_;
181
182  DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
183};
184
185CallbackAnimationObserver::CallbackAnimationObserver(
186    ui::LayerAnimator* animator, base::Callback<void(void)> callback)
187    : animator_(animator), callback_(callback) {
188}
189
190CallbackAnimationObserver::~CallbackAnimationObserver() {
191  animator_->RemoveObserver(this);
192}
193
194void CallbackAnimationObserver::OnLayerAnimationEnded(
195    ui::LayerAnimationSequence* seq) {
196  if (animator_->is_animating())
197    return;
198  animator_->RemoveObserver(this);
199  callback_.Run();
200}
201
202void CallbackAnimationObserver::OnLayerAnimationAborted(
203    ui::LayerAnimationSequence* seq) {
204  animator_->RemoveObserver(this);
205}
206
207class WindowBoundsChangeObserver : public aura::WindowObserver {
208 public:
209  virtual void OnWindowBoundsChanged(aura::Window* window,
210                                     const gfx::Rect& old_bounds,
211                                     const gfx::Rect& new_bounds) OVERRIDE;
212  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
213
214  void AddObservedWindow(aura::Window* window);
215  void RemoveAllObservedWindows();
216
217 private:
218  std::set<aura::Window*> observed_windows_;
219};
220
221void WindowBoundsChangeObserver::OnWindowBoundsChanged(aura::Window* window,
222    const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) {
223  KeyboardController* controller =  KeyboardController::GetInstance();
224  if (controller)
225    controller->UpdateWindowInsets(window);
226}
227
228void WindowBoundsChangeObserver::OnWindowDestroyed(aura::Window* window) {
229  if (window->HasObserver(this))
230    window->RemoveObserver(this);
231  observed_windows_.erase(window);
232}
233
234void WindowBoundsChangeObserver::AddObservedWindow(aura::Window* window) {
235  if (!window->HasObserver(this)) {
236    window->AddObserver(this);
237    observed_windows_.insert(window);
238  }
239}
240
241void WindowBoundsChangeObserver::RemoveAllObservedWindows() {
242  for (std::set<aura::Window*>::iterator it = observed_windows_.begin();
243       it != observed_windows_.end(); ++it)
244    (*it)->RemoveObserver(this);
245  observed_windows_.clear();
246}
247
248// static
249KeyboardController* KeyboardController::instance_ = NULL;
250
251KeyboardController::KeyboardController(KeyboardControllerProxy* proxy)
252    : proxy_(proxy),
253      input_method_(NULL),
254      keyboard_visible_(false),
255      show_on_resize_(false),
256      lock_keyboard_(false),
257      type_(ui::TEXT_INPUT_TYPE_NONE),
258      weak_factory_(this) {
259  CHECK(proxy);
260  input_method_ = proxy_->GetInputMethod();
261  input_method_->AddObserver(this);
262  window_bounds_observer_.reset(new WindowBoundsChangeObserver());
263}
264
265KeyboardController::~KeyboardController() {
266  if (container_)
267    container_->RemoveObserver(this);
268  if (input_method_)
269    input_method_->RemoveObserver(this);
270  ResetWindowInsets();
271}
272
273// static
274void KeyboardController::ResetInstance(KeyboardController* controller) {
275  if (instance_ && instance_ != controller)
276    delete instance_;
277  instance_ = controller;
278}
279
280// static
281KeyboardController* KeyboardController::GetInstance() {
282  return instance_;
283}
284
285aura::Window* KeyboardController::GetContainerWindow() {
286  if (!container_.get()) {
287    container_.reset(new aura::Window(
288        new KeyboardWindowDelegate(proxy_.get())));
289    container_->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
290        new KeyboardContainerTargeter(container_.get(), proxy_.get())));
291    container_->SetName("KeyboardContainer");
292    container_->set_owned_by_parent(false);
293    container_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
294    container_->AddObserver(this);
295    container_->SetLayoutManager(new KeyboardLayoutManager(this));
296  }
297  return container_.get();
298}
299
300void KeyboardController::NotifyKeyboardBoundsChanging(
301    const gfx::Rect& new_bounds) {
302  current_keyboard_bounds_ = new_bounds;
303  if (proxy_->HasKeyboardWindow() && proxy_->GetKeyboardWindow()->IsVisible()) {
304    FOR_EACH_OBSERVER(KeyboardControllerObserver,
305                      observer_list_,
306                      OnKeyboardBoundsChanging(new_bounds));
307    if (keyboard::IsKeyboardOverscrollEnabled()) {
308      // Adjust the height of the viewport for visible windows on the primary
309      // display.
310      // TODO(kevers): Add EnvObserver to properly initialize insets if a
311      // window is created while the keyboard is visible.
312      scoped_ptr<content::RenderWidgetHostIterator> widgets(
313          content::RenderWidgetHost::GetRenderWidgetHosts());
314      aura::Window *keyboard_window = proxy_->GetKeyboardWindow();
315      aura::Window *root_window = keyboard_window->GetRootWindow();
316      while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
317        content::RenderWidgetHostView* view = widget->GetView();
318        // Can be NULL, e.g. if the RenderWidget is being destroyed or
319        // the render process crashed.
320        if (view) {
321          aura::Window *window = view->GetNativeView();
322          // If virtual keyboard failed to load, a widget that displays error
323          // message will be created and adds as a child of the virtual keyboard
324          // window. We want to avoid add BoundsChangedObserver to that window.
325          if (GetFrameWindow(window) != keyboard_window &&
326              window->GetRootWindow() == root_window) {
327            gfx::Rect window_bounds = window->GetBoundsInScreen();
328            gfx::Rect intersect = gfx::IntersectRects(window_bounds,
329                                                      new_bounds);
330            int overlap = intersect.height();
331            if (overlap > 0 && overlap < window_bounds.height())
332              view->SetInsets(gfx::Insets(0, 0, overlap, 0));
333            else
334              view->SetInsets(gfx::Insets());
335            AddBoundsChangedObserver(window);
336          }
337        }
338      }
339    } else {
340      ResetWindowInsets();
341    }
342  } else {
343    current_keyboard_bounds_ = gfx::Rect();
344  }
345}
346
347void KeyboardController::HideKeyboard(HideReason reason) {
348  keyboard_visible_ = false;
349  ToggleTouchEventLogging(true);
350
351  keyboard::LogKeyboardControlEvent(
352      reason == HIDE_REASON_AUTOMATIC ?
353          keyboard::KEYBOARD_CONTROL_HIDE_AUTO :
354          keyboard::KEYBOARD_CONTROL_HIDE_USER);
355
356  NotifyKeyboardBoundsChanging(gfx::Rect());
357
358  set_lock_keyboard(false);
359
360  ui::LayerAnimator* container_animator = container_->layer()->GetAnimator();
361  animation_observer_.reset(new CallbackAnimationObserver(
362      container_animator,
363      base::Bind(&KeyboardController::HideAnimationFinished,
364                 base::Unretained(this))));
365  container_animator->AddObserver(animation_observer_.get());
366
367  ui::ScopedLayerAnimationSettings settings(container_animator);
368  settings.SetTweenType(gfx::Tween::FAST_OUT_LINEAR_IN);
369  settings.SetTransitionDuration(
370      base::TimeDelta::FromMilliseconds(kHideAnimationDurationMs));
371  gfx::Transform transform;
372  transform.Translate(0, kAnimationDistance);
373  container_->SetTransform(transform);
374  container_->layer()->SetOpacity(kAnimationStartOrAfterHideOpacity);
375}
376
377void KeyboardController::AddObserver(KeyboardControllerObserver* observer) {
378  observer_list_.AddObserver(observer);
379}
380
381void KeyboardController::RemoveObserver(KeyboardControllerObserver* observer) {
382  observer_list_.RemoveObserver(observer);
383}
384
385void KeyboardController::ShowKeyboard(bool lock) {
386  set_lock_keyboard(lock);
387  ShowKeyboardInternal();
388}
389
390void KeyboardController::OnWindowHierarchyChanged(
391    const HierarchyChangeParams& params) {
392  if (params.new_parent && params.target == container_.get())
393    OnTextInputStateChanged(proxy_->GetInputMethod()->GetTextInputClient());
394}
395
396void KeyboardController::Reload() {
397  if (proxy_->HasKeyboardWindow()) {
398    // A reload should never try to show virtual keyboard. If keyboard is not
399    // visible before reload, it should keep invisible after reload.
400    show_on_resize_ = false;
401    proxy_->ReloadKeyboardIfNeeded();
402  }
403}
404
405void KeyboardController::OnTextInputStateChanged(
406    const ui::TextInputClient* client) {
407  if (!container_.get())
408    return;
409
410  type_ = client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE;
411
412  if (type_ == ui::TEXT_INPUT_TYPE_NONE && !lock_keyboard_) {
413    if (keyboard_visible_) {
414      // Set the visibility state here so that any queries for visibility
415      // before the timer fires returns the correct future value.
416      keyboard_visible_ = false;
417      base::MessageLoop::current()->PostDelayedTask(
418          FROM_HERE,
419          base::Bind(&KeyboardController::HideKeyboard,
420                     weak_factory_.GetWeakPtr(), HIDE_REASON_AUTOMATIC),
421          base::TimeDelta::FromMilliseconds(kHideKeyboardDelayMs));
422    }
423  } else {
424    // Abort a pending keyboard hide.
425    if (WillHideKeyboard()) {
426      weak_factory_.InvalidateWeakPtrs();
427      keyboard_visible_ = true;
428    }
429    proxy_->SetUpdateInputType(type_);
430    // Do not explicitly show the Virtual keyboard unless it is in the process
431    // of hiding. Instead, the virtual keyboard is shown in response to a user
432    // gesture (mouse or touch) that is received while an element has input
433    // focus. Showing the keyboard requires an explicit call to
434    // OnShowImeIfNeeded.
435  }
436}
437
438void KeyboardController::OnInputMethodDestroyed(
439    const ui::InputMethod* input_method) {
440  DCHECK_EQ(input_method_, input_method);
441  input_method_ = NULL;
442}
443
444void KeyboardController::OnShowImeIfNeeded() {
445  ShowKeyboardInternal();
446}
447
448bool KeyboardController::ShouldEnableInsets(aura::Window* window) {
449  aura::Window *keyboard_window = proxy_->GetKeyboardWindow();
450  return (keyboard_window->GetRootWindow() == window->GetRootWindow() &&
451          keyboard::IsKeyboardOverscrollEnabled() &&
452          proxy_->GetKeyboardWindow()->IsVisible() &&
453          keyboard_visible_);
454}
455
456void KeyboardController::UpdateWindowInsets(aura::Window* window) {
457  aura::Window *keyboard_window = proxy_->GetKeyboardWindow();
458  if (window == keyboard_window)
459    return;
460
461  scoped_ptr<content::RenderWidgetHostIterator> widgets(
462      content::RenderWidgetHost::GetRenderWidgetHosts());
463  while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
464    content::RenderWidgetHostView* view = widget->GetView();
465    if (view && window->Contains(view->GetNativeView())) {
466      gfx::Rect window_bounds = view->GetNativeView()->GetBoundsInScreen();
467      gfx::Rect intersect = gfx::IntersectRects(window_bounds,
468          proxy_->GetKeyboardWindow()->bounds());
469      int overlap = ShouldEnableInsets(window) ? intersect.height() : 0;
470      if (overlap > 0 && overlap < window_bounds.height())
471        view->SetInsets(gfx::Insets(0, 0, overlap, 0));
472      else
473        view->SetInsets(gfx::Insets());
474      return;
475    }
476  }
477}
478
479void KeyboardController::ShowKeyboardInternal() {
480  if (!container_.get())
481    return;
482
483  if (container_->children().empty()) {
484    keyboard::MarkKeyboardLoadStarted();
485    aura::Window* keyboard = proxy_->GetKeyboardWindow();
486    keyboard->Show();
487    container_->AddChild(keyboard);
488    keyboard->set_owned_by_parent(false);
489  }
490
491  proxy_->ReloadKeyboardIfNeeded();
492
493  if (keyboard_visible_) {
494    return;
495  } else if (proxy_->GetKeyboardWindow()->bounds().height() == 0) {
496    show_on_resize_ = true;
497    return;
498  }
499
500  keyboard_visible_ = true;
501
502  // If the controller is in the process of hiding the keyboard, do not log
503  // the stat here since the keyboard will not actually be shown.
504  if (!WillHideKeyboard())
505    keyboard::LogKeyboardControlEvent(keyboard::KEYBOARD_CONTROL_SHOW);
506
507  weak_factory_.InvalidateWeakPtrs();
508
509  // If |container_| has hide animation, its visibility is set to false when
510  // hide animation finished. So even if the container is visible at this
511  // point, it may in the process of hiding. We still need to show keyboard
512  // container in this case.
513  if (container_->IsVisible() &&
514      !container_->layer()->GetAnimator()->is_animating())
515    return;
516
517  ToggleTouchEventLogging(false);
518  ui::LayerAnimator* container_animator = container_->layer()->GetAnimator();
519
520  // If the container is not animating, makes sure the position and opacity
521  // are at begin states for animation.
522  if (!container_animator->is_animating()) {
523    gfx::Transform transform;
524    transform.Translate(0, kAnimationDistance);
525    container_->SetTransform(transform);
526    container_->layer()->SetOpacity(kAnimationStartOrAfterHideOpacity);
527  }
528
529  container_animator->set_preemption_strategy(
530      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
531  animation_observer_.reset(new CallbackAnimationObserver(
532      container_animator,
533      base::Bind(&KeyboardController::ShowAnimationFinished,
534                 base::Unretained(this))));
535  container_animator->AddObserver(animation_observer_.get());
536
537  proxy_->ShowKeyboardContainer(container_.get());
538
539  {
540    // Scope the following animation settings as we don't want to animate
541    // visibility change that triggered by a call to the base class function
542    // ShowKeyboardContainer with these settings. The container should become
543    // visible immediately.
544    ui::ScopedLayerAnimationSettings settings(container_animator);
545    settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN);
546    settings.SetTransitionDuration(
547        base::TimeDelta::FromMilliseconds(kShowAnimationDurationMs));
548    container_->SetTransform(gfx::Transform());
549    container_->layer()->SetOpacity(1.0);
550  }
551}
552
553void KeyboardController::ResetWindowInsets() {
554  const gfx::Insets insets;
555  scoped_ptr<content::RenderWidgetHostIterator> widgets(
556      content::RenderWidgetHost::GetRenderWidgetHosts());
557  while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
558    content::RenderWidgetHostView* view = widget->GetView();
559    if (view)
560      view->SetInsets(insets);
561  }
562  window_bounds_observer_->RemoveAllObservedWindows();
563}
564
565bool KeyboardController::WillHideKeyboard() const {
566  return weak_factory_.HasWeakPtrs();
567}
568
569void KeyboardController::ShowAnimationFinished() {
570  // Notify observers after animation finished to prevent reveal desktop
571  // background during animation.
572  NotifyKeyboardBoundsChanging(proxy_->GetKeyboardWindow()->bounds());
573  proxy_->EnsureCaretInWorkArea();
574}
575
576void KeyboardController::HideAnimationFinished() {
577  proxy_->HideKeyboardContainer(container_.get());
578}
579
580void KeyboardController::AddBoundsChangedObserver(aura::Window* window) {
581  aura::Window* target_window = GetFrameWindow(window);
582  if (target_window)
583    window_bounds_observer_->AddObservedWindow(target_window);
584}
585
586}  // namespace keyboard
587