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_proxy.h" 6 7#include "base/command_line.h" 8#include "base/values.h" 9#include "content/public/browser/site_instance.h" 10#include "content/public/browser/web_contents.h" 11#include "content/public/browser/web_contents.h" 12#include "content/public/browser/web_contents_delegate.h" 13#include "content/public/browser/web_contents_observer.h" 14#include "content/public/browser/web_ui.h" 15#include "content/public/common/bindings_policy.h" 16#include "ui/aura/layout_manager.h" 17#include "ui/aura/window.h" 18#include "ui/base/ime/input_method.h" 19#include "ui/base/ime/text_input_client.h" 20#include "ui/keyboard/keyboard_constants.h" 21#include "ui/keyboard/keyboard_switches.h" 22#include "ui/keyboard/keyboard_util.h" 23#include "ui/wm/core/shadow.h" 24 25namespace { 26 27// The WebContentsDelegate for the keyboard. 28// The delegate deletes itself when the keyboard is destroyed. 29class KeyboardContentsDelegate : public content::WebContentsDelegate, 30 public content::WebContentsObserver { 31 public: 32 KeyboardContentsDelegate(keyboard::KeyboardControllerProxy* proxy) 33 : proxy_(proxy) {} 34 virtual ~KeyboardContentsDelegate() {} 35 36 private: 37 // Overridden from content::WebContentsDelegate: 38 virtual content::WebContents* OpenURLFromTab( 39 content::WebContents* source, 40 const content::OpenURLParams& params) OVERRIDE { 41 source->GetController().LoadURL( 42 params.url, params.referrer, params.transition, params.extra_headers); 43 Observe(source); 44 return source; 45 } 46 47 virtual bool IsPopupOrPanel( 48 const content::WebContents* source) const OVERRIDE { 49 return true; 50 } 51 52 virtual void MoveContents(content::WebContents* source, 53 const gfx::Rect& pos) OVERRIDE { 54 aura::Window* keyboard = proxy_->GetKeyboardWindow(); 55 // keyboard window must have been added to keyboard container window at this 56 // point. Otherwise, wrong keyboard bounds is used and may cause problem as 57 // described in crbug.com/367788. 58 DCHECK(keyboard->parent()); 59 gfx::Rect bounds = keyboard->bounds(); 60 int new_height = pos.height(); 61 bounds.set_y(bounds.y() + bounds.height() - new_height); 62 bounds.set_height(new_height); 63 keyboard->SetBounds(bounds); 64 } 65 66 // Overridden from content::WebContentsDelegate: 67 virtual void RequestMediaAccessPermission(content::WebContents* web_contents, 68 const content::MediaStreamRequest& request, 69 const content::MediaResponseCallback& callback) OVERRIDE { 70 proxy_->RequestAudioInput(web_contents, request, callback); 71 } 72 73 // Overridden from content::WebContentsObserver: 74 virtual void WebContentsDestroyed() OVERRIDE { 75 delete this; 76 } 77 78 keyboard::KeyboardControllerProxy* proxy_; 79 80 DISALLOW_COPY_AND_ASSIGN(KeyboardContentsDelegate); 81}; 82 83} // namespace 84 85namespace keyboard { 86 87KeyboardControllerProxy::KeyboardControllerProxy() 88 : default_url_(kKeyboardURL) { 89} 90 91KeyboardControllerProxy::~KeyboardControllerProxy() { 92} 93 94const GURL& KeyboardControllerProxy::GetVirtualKeyboardUrl() { 95 if (keyboard::IsInputViewEnabled()) { 96 const GURL& override_url = GetOverrideContentUrl(); 97 return override_url.is_valid() ? override_url : default_url_; 98 } else { 99 return default_url_; 100 } 101} 102 103void KeyboardControllerProxy::LoadContents(const GURL& url) { 104 if (keyboard_contents_) { 105 content::OpenURLParams params( 106 url, 107 content::Referrer(), 108 SINGLETON_TAB, 109 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, 110 false); 111 keyboard_contents_->OpenURL(params); 112 } 113} 114 115aura::Window* KeyboardControllerProxy::GetKeyboardWindow() { 116 if (!keyboard_contents_) { 117 content::BrowserContext* context = GetBrowserContext(); 118 keyboard_contents_.reset(content::WebContents::Create( 119 content::WebContents::CreateParams(context, 120 content::SiteInstance::CreateForURL(context, 121 GetVirtualKeyboardUrl())))); 122 keyboard_contents_->SetDelegate(new KeyboardContentsDelegate(this)); 123 SetupWebContents(keyboard_contents_.get()); 124 LoadContents(GetVirtualKeyboardUrl()); 125 keyboard_contents_->GetNativeView()->AddObserver(this); 126 } 127 128 return keyboard_contents_->GetNativeView(); 129} 130 131bool KeyboardControllerProxy::HasKeyboardWindow() const { 132 return keyboard_contents_; 133} 134 135void KeyboardControllerProxy::ShowKeyboardContainer(aura::Window* container) { 136 GetKeyboardWindow()->Show(); 137 container->Show(); 138} 139 140void KeyboardControllerProxy::HideKeyboardContainer(aura::Window* container) { 141 container->Hide(); 142 GetKeyboardWindow()->Hide(); 143} 144 145void KeyboardControllerProxy::SetUpdateInputType(ui::TextInputType type) { 146} 147 148void KeyboardControllerProxy::EnsureCaretInWorkArea() { 149 if (GetInputMethod()->GetTextInputClient()) { 150 aura::Window* keyboard_window = GetKeyboardWindow(); 151 aura::Window* root_window = keyboard_window->GetRootWindow(); 152 gfx::Rect available_bounds = root_window->bounds(); 153 gfx::Rect keyboard_bounds = keyboard_window->bounds(); 154 available_bounds.set_height(available_bounds.height() - 155 keyboard_bounds.height()); 156 GetInputMethod()->GetTextInputClient()->EnsureCaretInRect(available_bounds); 157 } 158} 159 160void KeyboardControllerProxy::LoadSystemKeyboard() { 161 DCHECK(keyboard_contents_); 162 if (keyboard_contents_->GetURL() != default_url_) { 163 // TODO(bshe): The height of system virtual keyboard and IME virtual 164 // keyboard may different. The height needs to be restored too. 165 LoadContents(default_url_); 166 } 167} 168 169void KeyboardControllerProxy::ReloadKeyboardIfNeeded() { 170 DCHECK(keyboard_contents_); 171 if (keyboard_contents_->GetURL() != GetVirtualKeyboardUrl()) { 172 if (keyboard_contents_->GetURL().GetOrigin() != 173 GetVirtualKeyboardUrl().GetOrigin()) { 174 // Sets keyboard window height to 0 before navigate to a keyboard in a 175 // different extension. This keeps the UX the same as Android. 176 gfx::Rect bounds = GetKeyboardWindow()->bounds(); 177 bounds.set_y(bounds.y() + bounds.height()); 178 bounds.set_height(0); 179 GetKeyboardWindow()->SetBounds(bounds); 180 } 181 LoadContents(GetVirtualKeyboardUrl()); 182 } 183} 184 185void KeyboardControllerProxy::SetupWebContents(content::WebContents* contents) { 186} 187 188void KeyboardControllerProxy::OnWindowBoundsChanged( 189 aura::Window* window, 190 const gfx::Rect& old_bounds, 191 const gfx::Rect& new_bounds) { 192 if (!shadow_) { 193 shadow_.reset(new wm::Shadow()); 194 shadow_->Init(wm::Shadow::STYLE_ACTIVE); 195 shadow_->layer()->SetVisible(true); 196 DCHECK(keyboard_contents_->GetNativeView()->parent()); 197 keyboard_contents_->GetNativeView()->parent()->layer()->Add( 198 shadow_->layer()); 199 } 200 201 shadow_->SetContentBounds(new_bounds); 202} 203 204void KeyboardControllerProxy::OnWindowDestroyed(aura::Window* window) { 205 window->RemoveObserver(this); 206} 207 208} // namespace keyboard 209