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