Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(212)

Side by Side Diff: chrome/browser/ui/touch/keyboard/keyboard_manager.cc

Issue 8044018: Move chrome/browser/ui/touch/keyboard* to chrome/browser/ui/virtual_keyboard/ (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Merged ToT Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome/browser/ui/touch/keyboard/keyboard_manager.h"
6
7 #include "base/json/json_writer.h"
8 #include "base/values.h"
9 #include "chrome/browser/extensions/extension_event_router.h"
10 #include "chrome/browser/extensions/extension_function_dispatcher.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/profiles/profile_manager.h"
13 #include "chrome/browser/tabs/tab_strip_model.h"
14 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
15 #include "chrome/browser/ui/views/dom_view.h"
16 #include "chrome/common/chrome_notification_types.h"
17 #include "chrome/common/extensions/extension_messages.h"
18 #include "chrome/common/url_constants.h"
19 #include "content/browser/site_instance.h"
20 #include "content/browser/tab_contents/tab_contents_observer.h"
21 #include "content/common/notification_service.h"
22 #include "ui/base/animation/animation_delegate.h"
23 #include "ui/base/animation/slide_animation.h"
24 #include "ui/base/ime/text_input_type.h"
25 #include "ui/gfx/compositor/layer.h"
26 #include "ui/gfx/interpolated_transform.h"
27 #include "ui/gfx/screen.h"
28 #include "views/ime/text_input_type_tracker.h"
29 #include "views/widget/widget.h"
30
31 #if defined(OS_CHROMEOS)
32 #include "chrome/browser/chromeos/input_method/input_method_manager.h"
33 #include "chrome/browser/chromeos/input_method/virtual_keyboard_selector.h"
34 #endif
35
36 namespace {
37
38 const int kDefaultKeyboardHeight = 300;
39 const int kKeyboardSlideDuration = 300; // In milliseconds
40 const char kOnTextInputTypeChanged[] =
41 "experimental.input.onTextInputTypeChanged";
42
43 // The default position of the keyboard widget should be at the bottom,
44 // spanning the entire width of the desktop.
45 gfx::Rect GetKeyboardPosition(int height) {
46 views::View* desktop = views::desktop::DesktopWindowView::desktop_window_view;
47 gfx::Rect area;
48 if (desktop)
49 area = desktop->bounds();
50 else
51 area = gfx::Screen::GetMonitorAreaNearestPoint(gfx::Point());
52 return gfx::Rect(area.x(), area.y() + area.height() - height,
53 area.width(), height);
54 }
55
56 } // namespace
57
58 // TODO(sad): Is the default profile always going to be the one we want?
59
60 class KeyboardWidget
61 : public views::Widget,
62 public ui::AnimationDelegate,
63 public TabContentsObserver,
64 public ExtensionFunctionDispatcher::Delegate,
65 #if defined(OS_CHROMEOS)
66 public chromeos::input_method::InputMethodManager::VirtualKeyboardObserver ,
67 #endif
68 public NotificationObserver,
69 public views::Widget::Observer,
70 public views::TextInputTypeObserver {
71 public:
72 KeyboardWidget();
73 virtual ~KeyboardWidget();
74
75 // Show the keyboard for the target widget. The events from the keyboard will
76 // be sent to |widget|.
77 // TODO(sad): Allow specifying the type of keyboard to show.
78 void ShowKeyboardForWidget(views::Widget* widget);
79
80 // Updates the bounds to reflect the current screen/desktop bounds.
81 void ResetBounds();
82
83 // Overridden from views::Widget
84 void Hide() OVERRIDE;
85
86 private:
87 // Sets the target widget, adds/removes Widget::Observer, reparents etc.
88 void SetTarget(Widget* target);
89
90 // Overridden from views::Widget.
91 virtual bool OnKeyEvent(const views::KeyEvent& event) OVERRIDE;
92
93 // Overridden from ui::AnimationDelegate.
94 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
95 virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
96
97 // Overridden from TabContentsObserver.
98 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
99 void OnRequest(const ExtensionHostMsg_Request_Params& params);
100
101 // Overridden from TextInputTypeObserver.
102 virtual void TextInputTypeChanged(ui::TextInputType type,
103 views::Widget *widget) OVERRIDE;
104
105 // Overridden from ExtensionFunctionDispatcher::Delegate.
106 virtual Browser* GetBrowser() OVERRIDE;
107 virtual gfx::NativeView GetNativeViewOfHost() OVERRIDE;
108 virtual TabContents* GetAssociatedTabContents() const OVERRIDE;
109
110 #if defined(OS_CHROMEOS)
111 // Overridden from input_method::InputMethodManager::VirtualKeyboardObserver.
112 virtual void VirtualKeyboardChanged(
113 chromeos::input_method::InputMethodManager* manager,
114 const chromeos::input_method::VirtualKeyboard& virtual_keyboard,
115 const std::string& virtual_keyboard_layout);
116 #endif
117
118 // Overridden from NotificationObserver.
119 virtual void Observe(int type,
120 const NotificationSource& source,
121 const NotificationDetails& details) OVERRIDE;
122
123 // Overridden from views::Widget::Observer.
124 virtual void OnWidgetClosing(Widget* widget) OVERRIDE;
125 virtual void OnWidgetVisibilityChanged(Widget* widget, bool visible) OVERRIDE;
126 virtual void OnWidgetActivationChanged(Widget* widget, bool active) OVERRIDE;
127
128 // The animation.
129 scoped_ptr<ui::SlideAnimation> animation_;
130
131 // Interpolated transform used during animation.
132 scoped_ptr<ui::InterpolatedTransform> transform_;
133
134 // The DOM view to host the keyboard.
135 DOMView* dom_view_;
136
137 ExtensionFunctionDispatcher extension_dispatcher_;
138
139 // The widget the events from the keyboard should be directed to.
140 views::Widget* target_;
141
142 // Height of the keyboard.
143 int keyboard_height_;
144
145 NotificationRegistrar registrar_;
146
147 DISALLOW_COPY_AND_ASSIGN(KeyboardWidget);
148 };
149
150 KeyboardWidget::KeyboardWidget()
151 : views::Widget::Widget(),
152 dom_view_(new DOMView),
153 ALLOW_THIS_IN_INITIALIZER_LIST(
154 extension_dispatcher_(ProfileManager::GetDefaultProfile(), this)),
155 target_(NULL),
156 keyboard_height_(kDefaultKeyboardHeight) {
157
158 // Initialize the widget first.
159 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
160 params.keep_on_top = true;
161 params.transparent = true;
162 params.bounds = GetKeyboardPosition(keyboard_height_);
163 Init(params);
164
165 // Setup the DOM view to host the keyboard.
166 Profile* profile = ProfileManager::GetDefaultProfile();
167 GURL keyboard_url(chrome::kChromeUIKeyboardURL);
168 dom_view_->Init(profile,
169 SiteInstance::CreateSiteInstanceForURL(profile, keyboard_url));
170 dom_view_->LoadURL(keyboard_url);
171 dom_view_->SetVisible(true);
172 SetContentsView(dom_view_);
173
174 // Setup observer so the events from the keyboard can be handled.
175 TabContentsObserver::Observe(dom_view_->tab_contents());
176
177 // Initialize the animation.
178 animation_.reset(new ui::SlideAnimation(this));
179 animation_->SetTweenType(ui::Tween::LINEAR);
180 animation_->SetSlideDuration(kKeyboardSlideDuration);
181
182 views::TextInputTypeTracker::GetInstance()->AddTextInputTypeObserver(this);
183 registrar_.Add(this,
184 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED,
185 NotificationService::AllSources());
186 registrar_.Add(this,
187 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED,
188 NotificationService::AllSources());
189 registrar_.Add(this,
190 content::NOTIFICATION_APP_TERMINATING,
191 NotificationService::AllSources());
192
193 #if defined(OS_CHROMEOS)
194 chromeos::input_method::InputMethodManager* manager =
195 chromeos::input_method::InputMethodManager::GetInstance();
196 manager->AddVirtualKeyboardObserver(this);
197 #endif
198 }
199
200 KeyboardWidget::~KeyboardWidget() {
201 if (target_)
202 target_->RemoveObserver(this);
203 views::TextInputTypeTracker::GetInstance()->RemoveTextInputTypeObserver(this);
204 #if defined(OS_CHROMEOS)
205 chromeos::input_method::InputMethodManager* manager =
206 chromeos::input_method::InputMethodManager::GetInstance();
207 manager->RemoveVirtualKeyboardObserver(this);
208 #endif
209
210 // TODO(sad): Do anything else?
211 }
212
213 void KeyboardWidget::ShowKeyboardForWidget(views::Widget* widget) {
214 SetTarget(widget);
215
216 transform_.reset(new ui::InterpolatedTranslation(
217 gfx::Point(0, keyboard_height_), gfx::Point()));
218
219 GetRootView()->SetTransform(
220 transform_->Interpolate(animation_->GetCurrentValue()));
221 animation_->Show();
222
223 Show();
224
225 bool visible = true;
226 NotificationService::current()->Notify(
227 chrome::NOTIFICATION_KEYBOARD_VISIBILITY_CHANGED,
228 Source<KeyboardWidget>(this),
229 Details<bool>(&visible));
230 }
231
232 void KeyboardWidget::ResetBounds() {
233 SetBounds(GetKeyboardPosition(keyboard_height_));
234 }
235
236 void KeyboardWidget::Hide() {
237 animation_->Hide();
238
239 bool visible = false;
240 NotificationService::current()->Notify(
241 chrome::NOTIFICATION_KEYBOARD_VISIBILITY_CHANGED,
242 Source<KeyboardWidget>(this),
243 Details<bool>(&visible));
244 }
245
246 void KeyboardWidget::SetTarget(views::Widget* target) {
247 if (target_)
248 target_->RemoveObserver(this);
249
250 target_ = target;
251
252 if (target_) {
253 // TODO(sad): Make |target_| the parent widget.
254 target_->AddObserver(this);
255 } else if (IsVisible()) {
256 Hide();
257 }
258 }
259
260 bool KeyboardWidget::OnKeyEvent(const views::KeyEvent& event) {
261 return target_ ? target_->OnKeyEvent(event) : false;
262 }
263
264 void KeyboardWidget::AnimationProgressed(const ui::Animation* animation) {
265 float t = static_cast<float>(animation_->GetCurrentValue());
266 if (GetRootView()->layer())
267 GetRootView()->layer()->SetOpacity(t * t);
268 GetRootView()->SetTransform(transform_->Interpolate(t));
269 }
270
271 void KeyboardWidget::AnimationEnded(const ui::Animation* animation) {
272 gfx::Rect keyboard_rect;
273 if (animation_->GetCurrentValue() < 0.01)
274 Widget::Hide();
275 else
276 keyboard_rect = GetWindowScreenBounds();
277
278 NotificationService::current()->Notify(
279 chrome::NOTIFICATION_KEYBOARD_VISIBLE_BOUNDS_CHANGED,
280 Source<KeyboardWidget>(this),
281 Details<gfx::Rect>(&keyboard_rect));
282 }
283
284 bool KeyboardWidget::OnMessageReceived(const IPC::Message& message) {
285 bool handled = true;
286 IPC_BEGIN_MESSAGE_MAP(KeyboardWidget, message)
287 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
288 IPC_MESSAGE_UNHANDLED(handled = false)
289 IPC_END_MESSAGE_MAP()
290 return handled;
291 }
292
293 void KeyboardWidget::OnRequest(const ExtensionHostMsg_Request_Params& request) {
294 extension_dispatcher_.Dispatch(request,
295 dom_view_->tab_contents()->render_view_host());
296 }
297
298 void KeyboardWidget::TextInputTypeChanged(ui::TextInputType type,
299 views::Widget *widget) {
300 // Send onTextInputTypeChanged event to keyboard extension.
301 ListValue args;
302 switch (type) {
303 case ui::TEXT_INPUT_TYPE_NONE: {
304 args.Append(Value::CreateStringValue("none"));
305 break;
306 }
307 case ui::TEXT_INPUT_TYPE_TEXT: {
308 args.Append(Value::CreateStringValue("text"));
309 break;
310 }
311 case ui::TEXT_INPUT_TYPE_PASSWORD: {
312 args.Append(Value::CreateStringValue("password"));
313 break;
314 }
315 case ui::TEXT_INPUT_TYPE_SEARCH: {
316 args.Append(Value::CreateStringValue("search"));
317 break;
318 }
319 case ui::TEXT_INPUT_TYPE_EMAIL: {
320 args.Append(Value::CreateStringValue("email"));
321 break;
322 }
323 case ui::TEXT_INPUT_TYPE_NUMBER: {
324 args.Append(Value::CreateStringValue("number"));
325 break;
326 }
327 case ui::TEXT_INPUT_TYPE_TELEPHONE: {
328 args.Append(Value::CreateStringValue("tel"));
329 break;
330 }
331 case ui::TEXT_INPUT_TYPE_URL: {
332 args.Append(Value::CreateStringValue("url"));
333 break;
334 }
335 default: {
336 NOTREACHED();
337 args.Append(Value::CreateStringValue("none"));
338 break;
339 }
340 }
341
342 std::string json_args;
343 base::JSONWriter::Write(&args, false, &json_args);
344
345 Profile* profile =
346 Profile::FromBrowserContext(dom_view_->tab_contents()->browser_context());
347 profile->GetExtensionEventRouter()->DispatchEventToRenderers(
348 kOnTextInputTypeChanged, json_args, NULL, GURL());
349
350 if (type == ui::TEXT_INPUT_TYPE_NONE)
351 Hide();
352 else
353 ShowKeyboardForWidget(widget);
354 }
355
356 Browser* KeyboardWidget::GetBrowser() {
357 // TODO(sad): Find a better way. Perhaps just return NULL, and fix
358 // SendKeyboardEventInputFunction::GetTopLevelWidget to somehow interact with
359 // the WM to find the top level widget?
360 return BrowserList::GetLastActive();
361 }
362
363 gfx::NativeView KeyboardWidget::GetNativeViewOfHost() {
364 return dom_view_->native_view();
365 }
366
367 TabContents* KeyboardWidget::GetAssociatedTabContents() const {
368 return dom_view_->tab_contents();
369 }
370
371 #if defined(OS_CHROMEOS)
372 void KeyboardWidget::VirtualKeyboardChanged(
373 chromeos::input_method::InputMethodManager* manager,
374 const chromeos::input_method::VirtualKeyboard& virtual_keyboard,
375 const std::string& virtual_keyboard_layout) {
376 const GURL& url = virtual_keyboard.GetURLForLayout(virtual_keyboard_layout);
377 dom_view_->LoadURL(url);
378 VLOG(1) << "VirtualKeyboardChanged: Switched to " << url.spec();
379 }
380 #endif
381
382 void KeyboardWidget::Observe(int type,
383 const NotificationSource& source,
384 const NotificationDetails& details) {
385 switch (type) {
386 case chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED: {
387 Hide();
388 break;
389 }
390
391 case chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED: {
392 // The keyboard is resizing itself.
393
394 // TODO(penghuang) Allow extension conrtol the virtual keyboard directly
395 // instead of using Notification.
396 int height = *Details<int>(details).ptr();
397 if (height != keyboard_height_) {
398 DCHECK_GE(height, 0) << "Keyboard height should not be negative.";
399
400 int old_height = keyboard_height_;
401 keyboard_height_ = height;
402 gfx::Rect rect = GetWindowScreenBounds();
403 rect.set_y(rect.y() + old_height - keyboard_height_);
404 rect.set_height(keyboard_height_);
405 SetBounds(rect);
406
407 // TODO(sad): Notify the target widget that the size has changed so it
408 // can update its display accordingly if it wanted to.
409 }
410 break;
411 }
412
413 case content::NOTIFICATION_APP_TERMINATING: {
414 CloseNow();
415 break;
416 }
417
418 default:
419 NOTREACHED();
420 }
421 }
422
423 void KeyboardWidget::OnWidgetClosing(Widget* widget) {
424 if (target_ == widget)
425 SetTarget(NULL);
426 }
427
428 void KeyboardWidget::OnWidgetVisibilityChanged(Widget* widget, bool visible) {
429 if (target_ == widget && !visible)
430 SetTarget(NULL);
431 }
432
433 void KeyboardWidget::OnWidgetActivationChanged(Widget* widget, bool active) {
434 if (target_ == widget && !active)
435 SetTarget(NULL);
436 }
437
438 KeyboardManager::KeyboardManager()
439 : keyboard_(new KeyboardWidget()) {
440 keyboard_->AddObserver(this);
441
442 views::desktop::DesktopWindowView* desktop =
443 views::desktop::DesktopWindowView::desktop_window_view;
444
445 // We are either not in views desktop mode, or we are and we are not yet
446 // observing the desktop.
447 DCHECK(!desktop || !desktop->HasObserver(this));
448
449 if (desktop)
450 desktop->AddObserver(this);
451 }
452
453 KeyboardManager::~KeyboardManager() {
454 DCHECK(!keyboard_);
455
456 views::desktop::DesktopWindowView* desktop =
457 views::desktop::DesktopWindowView::desktop_window_view;
458
459 // We are either not in views desktop mode, or we are and we have been
460 // observing the desktop
461 DCHECK(!desktop || desktop->HasObserver(this));
462
463 if (desktop)
464 desktop->RemoveObserver(this);
465 }
466
467 void KeyboardManager::ShowKeyboardForWidget(views::Widget* widget) {
468 keyboard_->ShowKeyboardForWidget(widget);
469 }
470
471 void KeyboardManager::Hide() {
472 keyboard_->Hide();
473 }
474
475 views::Widget* KeyboardManager::keyboard() {
476 return keyboard_;
477 }
478
479 void KeyboardManager::OnWidgetClosing(views::Widget* widget) {
480 DCHECK_EQ(keyboard_, widget);
481 keyboard_ = NULL;
482 }
483
484 void KeyboardManager::OnDesktopBoundsChanged(const gfx::Rect& prev_bounds) {
485 keyboard_->ResetBounds();
486 }
487
488 // static
489 KeyboardManager* KeyboardManager::GetInstance() {
490 return Singleton<KeyboardManager>::get();
491 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/touch/keyboard/keyboard_manager.h ('k') | chrome/browser/ui/touch/keyboard/keyboard_manager_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698