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.
5 #include "ui/keyboard/keyboard_controller_proxy.h"
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"
27 // The WebContentsDelegate for the keyboard.
28 // The delegate deletes itself when the keyboard is destroyed.
29 class KeyboardContentsDelegate
: public content::WebContentsDelegate
,
30 public content::WebContentsObserver
{
32 KeyboardContentsDelegate(keyboard::KeyboardControllerProxy
* proxy
)
34 ~KeyboardContentsDelegate() override
{}
37 // Overridden from content::WebContentsDelegate:
38 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
);
47 bool IsPopupOrPanel(const content::WebContents
* source
) const override
{
51 void MoveContents(content::WebContents
* source
,
52 const gfx::Rect
& pos
) override
{
53 aura::Window
* keyboard
= proxy_
->GetKeyboardWindow();
54 // keyboard window must have been added to keyboard container window at this
55 // point. Otherwise, wrong keyboard bounds is used and may cause problem as
56 // described in crbug.com/367788.
57 DCHECK(keyboard
->parent());
58 gfx::Rect bounds
= keyboard
->bounds();
59 int new_height
= pos
.height();
60 bounds
.set_y(bounds
.y() + bounds
.height() - new_height
);
61 bounds
.set_height(new_height
);
62 // Keyboard bounds should only be reset when it actually changes. Otherwise
63 // it interrupts the initial animation of showing the keyboard. Described in
65 if (bounds
!= keyboard
->bounds())
66 keyboard
->SetBounds(bounds
);
69 // Overridden from content::WebContentsDelegate:
70 void RequestMediaAccessPermission(
71 content::WebContents
* web_contents
,
72 const content::MediaStreamRequest
& request
,
73 const content::MediaResponseCallback
& callback
) override
{
74 proxy_
->RequestAudioInput(web_contents
, request
, callback
);
77 // Overridden from content::WebContentsObserver:
78 void WebContentsDestroyed() override
{ delete this; }
80 keyboard::KeyboardControllerProxy
* proxy_
;
82 DISALLOW_COPY_AND_ASSIGN(KeyboardContentsDelegate
);
89 KeyboardControllerProxy::KeyboardControllerProxy(
90 content::BrowserContext
* context
)
91 : browser_context_(context
), default_url_(kKeyboardURL
) {
94 KeyboardControllerProxy::~KeyboardControllerProxy() {
97 const GURL
& KeyboardControllerProxy::GetVirtualKeyboardUrl() {
98 if (keyboard::IsInputViewEnabled()) {
99 const GURL
& override_url
= GetOverrideContentUrl();
100 return override_url
.is_valid() ? override_url
: default_url_
;
106 void KeyboardControllerProxy::LoadContents(const GURL
& url
) {
107 if (keyboard_contents_
) {
108 content::OpenURLParams
params(
112 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
114 keyboard_contents_
->OpenURL(params
);
118 aura::Window
* KeyboardControllerProxy::GetKeyboardWindow() {
119 if (!keyboard_contents_
) {
120 content::BrowserContext
* context
= browser_context();
121 keyboard_contents_
.reset(content::WebContents::Create(
122 content::WebContents::CreateParams(context
,
123 content::SiteInstance::CreateForURL(context
,
124 GetVirtualKeyboardUrl()))));
125 keyboard_contents_
->SetDelegate(new KeyboardContentsDelegate(this));
126 SetupWebContents(keyboard_contents_
.get());
127 LoadContents(GetVirtualKeyboardUrl());
128 keyboard_contents_
->GetNativeView()->AddObserver(this);
131 return keyboard_contents_
->GetNativeView();
134 bool KeyboardControllerProxy::HasKeyboardWindow() const {
135 return keyboard_contents_
;
138 void KeyboardControllerProxy::ShowKeyboardContainer(aura::Window
* container
) {
139 GetKeyboardWindow()->Show();
143 void KeyboardControllerProxy::HideKeyboardContainer(aura::Window
* container
) {
145 GetKeyboardWindow()->Hide();
148 void KeyboardControllerProxy::SetUpdateInputType(ui::TextInputType type
) {
151 void KeyboardControllerProxy::EnsureCaretInWorkArea() {
152 if (GetInputMethod()->GetTextInputClient()) {
153 aura::Window
* keyboard_window
= GetKeyboardWindow();
154 aura::Window
* root_window
= keyboard_window
->GetRootWindow();
155 gfx::Rect available_bounds
= root_window
->bounds();
156 gfx::Rect keyboard_bounds
= keyboard_window
->bounds();
157 available_bounds
.set_height(available_bounds
.height() -
158 keyboard_bounds
.height());
159 GetInputMethod()->GetTextInputClient()->EnsureCaretInRect(available_bounds
);
163 void KeyboardControllerProxy::LoadSystemKeyboard() {
164 DCHECK(keyboard_contents_
);
165 if (keyboard_contents_
->GetURL() != default_url_
) {
166 // TODO(bshe): The height of system virtual keyboard and IME virtual
167 // keyboard may different. The height needs to be restored too.
168 LoadContents(default_url_
);
172 void KeyboardControllerProxy::ReloadKeyboardIfNeeded() {
173 DCHECK(keyboard_contents_
);
174 if (keyboard_contents_
->GetURL() != GetVirtualKeyboardUrl()) {
175 if (keyboard_contents_
->GetURL().GetOrigin() !=
176 GetVirtualKeyboardUrl().GetOrigin()) {
177 // Sets keyboard window height to 0 before navigate to a keyboard in a
178 // different extension. This keeps the UX the same as Android.
179 gfx::Rect bounds
= GetKeyboardWindow()->bounds();
180 bounds
.set_y(bounds
.y() + bounds
.height());
181 bounds
.set_height(0);
182 GetKeyboardWindow()->SetBounds(bounds
);
184 LoadContents(GetVirtualKeyboardUrl());
188 void KeyboardControllerProxy::SetupWebContents(content::WebContents
* contents
) {
191 void KeyboardControllerProxy::OnWindowBoundsChanged(
192 aura::Window
* window
,
193 const gfx::Rect
& old_bounds
,
194 const gfx::Rect
& new_bounds
) {
196 shadow_
.reset(new wm::Shadow());
197 shadow_
->Init(wm::Shadow::STYLE_ACTIVE
);
198 shadow_
->layer()->SetVisible(true);
199 DCHECK(keyboard_contents_
->GetNativeView()->parent());
200 keyboard_contents_
->GetNativeView()->parent()->layer()->Add(
204 shadow_
->SetContentBounds(new_bounds
);
207 void KeyboardControllerProxy::OnWindowDestroyed(aura::Window
* window
) {
208 window
->RemoveObserver(this);
211 } // namespace keyboard