OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/touch/keyboard/keyboard_manager.h" | 5 #include "chrome/browser/ui/touch/keyboard/keyboard_manager.h" |
6 | 6 |
| 7 #include "base/json/json_writer.h" |
| 8 #include "base/values.h" |
| 9 #include "chrome/browser/extensions/extension_event_router.h" |
7 #include "chrome/browser/profiles/profile.h" | 10 #include "chrome/browser/profiles/profile.h" |
8 #include "chrome/browser/profiles/profile_manager.h" | 11 #include "chrome/browser/profiles/profile_manager.h" |
9 #include "chrome/browser/tabs/tab_strip_model.h" | 12 #include "chrome/browser/tabs/tab_strip_model.h" |
10 #include "chrome/browser/ui/browser_list.h" | 13 #include "chrome/browser/ui/browser_list.h" |
11 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 14 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
12 #include "chrome/browser/ui/views/dom_view.h" | 15 #include "chrome/browser/ui/views/dom_view.h" |
13 #include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h" | 16 #include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h" |
14 #include "chrome/common/extensions/extension_messages.h" | 17 #include "chrome/common/extensions/extension_messages.h" |
15 #include "chrome/common/chrome_notification_types.h" | 18 #include "chrome/common/chrome_notification_types.h" |
16 #include "chrome/common/url_constants.h" | 19 #include "chrome/common/url_constants.h" |
17 #include "content/browser/site_instance.h" | 20 #include "content/browser/site_instance.h" |
18 #include "content/browser/tab_contents/tab_contents.h" | 21 #include "content/browser/tab_contents/tab_contents.h" |
19 #include "content/common/notification_service.h" | 22 #include "content/common/notification_service.h" |
20 #include "ui/base/animation/slide_animation.h" | 23 #include "ui/base/animation/slide_animation.h" |
21 #include "ui/base/ime/text_input_type.h" | 24 #include "ui/base/ime/text_input_type.h" |
22 #include "ui/gfx/interpolated_transform.h" | 25 #include "ui/gfx/interpolated_transform.h" |
23 #include "views/ime/text_input_client.h" | 26 #include "views/ime/text_input_client.h" |
24 #include "views/widget/widget.h" | 27 #include "views/widget/widget.h" |
25 | 28 |
26 #if defined(OS_CHROMEOS) | 29 #if defined(OS_CHROMEOS) |
27 #include "chrome/browser/chromeos/input_method/virtual_keyboard_selector.h" | 30 #include "chrome/browser/chromeos/input_method/virtual_keyboard_selector.h" |
28 #endif | 31 #endif |
29 | 32 |
30 namespace { | 33 namespace { |
31 | 34 |
32 const int kDefaultKeyboardHeight = 300; | 35 const int kDefaultKeyboardHeight = 300; |
33 const int kKeyboardSlideDuration = 300; // In milliseconds | 36 const int kKeyboardSlideDuration = 300; // In milliseconds |
34 | 37 const char kOnTextInputTypeChanged[] = |
35 PropertyAccessor<bool>* GetFocusedStateAccessor() { | 38 "experimental.input.onTextInputTypeChanged"; |
36 static PropertyAccessor<bool> state; | |
37 return &state; | |
38 } | |
39 | |
40 // Returns whether the keyboard visibility should be affected by this tab. | |
41 bool TabContentsCanAffectKeyboard(const TabContents* tab_contents) { | |
42 // There may not be a browser, e.g. for the login window. But if there is | |
43 // a browser, then |tab_contents| should be the active tab. | |
44 Browser* browser = Browser::GetBrowserForController( | |
45 &tab_contents->controller(), NULL); | |
46 return browser == NULL || | |
47 (browser == BrowserList::GetLastActive() && | |
48 browser->GetSelectedTabContents() == tab_contents); | |
49 } | |
50 | 39 |
51 } // namespace | 40 } // namespace |
52 | 41 |
53 // TODO(sad): Is the default profile always going to be the one we want? | 42 // TODO(sad): Is the default profile always going to be the one we want? |
54 | 43 |
55 KeyboardManager::KeyboardManager() | 44 KeyboardManager::KeyboardManager() |
56 : views::Widget::Widget(), | 45 : views::Widget::Widget(), |
57 dom_view_(new DOMView), | 46 dom_view_(new DOMView), |
58 ALLOW_THIS_IN_INITIALIZER_LIST( | 47 ALLOW_THIS_IN_INITIALIZER_LIST( |
59 extension_dispatcher_(ProfileManager::GetDefaultProfile(), this)), | 48 extension_dispatcher_(ProfileManager::GetDefaultProfile(), this)), |
(...skipping 15 matching lines...) Expand all Loading... |
75 SetContentsView(dom_view_); | 64 SetContentsView(dom_view_); |
76 | 65 |
77 // Setup observer so the events from the keyboard can be handled. | 66 // Setup observer so the events from the keyboard can be handled. |
78 TabContentsObserver::Observe(dom_view_->tab_contents()); | 67 TabContentsObserver::Observe(dom_view_->tab_contents()); |
79 | 68 |
80 // Initialize the animation. | 69 // Initialize the animation. |
81 animation_.reset(new ui::SlideAnimation(this)); | 70 animation_.reset(new ui::SlideAnimation(this)); |
82 animation_->SetTweenType(ui::Tween::LINEAR); | 71 animation_->SetTweenType(ui::Tween::LINEAR); |
83 animation_->SetSlideDuration(kKeyboardSlideDuration); | 72 animation_->SetSlideDuration(kKeyboardSlideDuration); |
84 | 73 |
85 // Start listening to notifications to maintain the keyboard visibility, size | 74 views::TextInputTypeTracker::GetInstance()->AddTextInputTypeObserver(this); |
86 // etc. | |
87 registrar_.Add(this, | |
88 content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
89 NotificationService::AllSources()); | |
90 registrar_.Add(this, | |
91 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE, | |
92 NotificationService::AllSources()); | |
93 registrar_.Add(this, | |
94 content::NOTIFICATION_TAB_CONTENTS_DESTROYED, | |
95 NotificationService::AllSources()); | |
96 registrar_.Add(this, | 75 registrar_.Add(this, |
97 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED, | 76 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED, |
98 NotificationService::AllSources()); | 77 NotificationService::AllSources()); |
99 registrar_.Add(this, | 78 registrar_.Add(this, |
100 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED, | 79 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED, |
101 NotificationService::AllSources()); | 80 NotificationService::AllSources()); |
102 registrar_.Add(this, | 81 registrar_.Add(this, |
103 chrome::NOTIFICATION_EDITABLE_ELEMENT_TOUCHED, | 82 chrome::NOTIFICATION_EDITABLE_ELEMENT_TOUCHED, |
104 NotificationService::AllSources()); | 83 NotificationService::AllSources()); |
105 registrar_.Add(this, | 84 registrar_.Add(this, |
106 content::NOTIFICATION_APP_EXITING, | 85 content::NOTIFICATION_APP_EXITING, |
107 NotificationService::AllSources()); | 86 NotificationService::AllSources()); |
108 | 87 |
109 #if defined(OS_CHROMEOS) | 88 #if defined(OS_CHROMEOS) |
110 chromeos::input_method::InputMethodManager* manager = | 89 chromeos::input_method::InputMethodManager* manager = |
111 chromeos::input_method::InputMethodManager::GetInstance(); | 90 chromeos::input_method::InputMethodManager::GetInstance(); |
112 manager->AddVirtualKeyboardObserver(this); | 91 manager->AddVirtualKeyboardObserver(this); |
113 #endif | 92 #endif |
114 } | 93 } |
115 | 94 |
116 KeyboardManager::~KeyboardManager() { | 95 KeyboardManager::~KeyboardManager() { |
117 if (target_) | 96 if (target_) |
118 target_->RemoveObserver(this); | 97 target_->RemoveObserver(this); |
| 98 views::TextInputTypeTracker::GetInstance()->RemoveTextInputTypeObserver(this); |
119 #if defined(OS_CHROMEOS) | 99 #if defined(OS_CHROMEOS) |
120 chromeos::input_method::InputMethodManager* manager = | 100 chromeos::input_method::InputMethodManager* manager = |
121 chromeos::input_method::InputMethodManager::GetInstance(); | 101 chromeos::input_method::InputMethodManager::GetInstance(); |
122 manager->RemoveVirtualKeyboardObserver(this); | 102 manager->RemoveVirtualKeyboardObserver(this); |
123 #endif | 103 #endif |
124 // TODO(sad): Do anything else? | 104 // TODO(sad): Do anything else? |
125 } | 105 } |
126 | 106 |
127 void KeyboardManager::ShowKeyboardForWidget(views::Widget* widget) { | 107 void KeyboardManager::ShowKeyboardForWidget(views::Widget* widget) { |
128 SetTarget(widget); | 108 SetTarget(widget); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 void KeyboardManager::AnimationProgressed(const ui::Animation* animation) { | 148 void KeyboardManager::AnimationProgressed(const ui::Animation* animation) { |
169 GetRootView()->SetTransform( | 149 GetRootView()->SetTransform( |
170 transform_->Interpolate(animation_->GetCurrentValue())); | 150 transform_->Interpolate(animation_->GetCurrentValue())); |
171 } | 151 } |
172 | 152 |
173 void KeyboardManager::AnimationEnded(const ui::Animation* animation) { | 153 void KeyboardManager::AnimationEnded(const ui::Animation* animation) { |
174 if (animation_->GetCurrentValue() < 0.01) | 154 if (animation_->GetCurrentValue() < 0.01) |
175 Widget::Hide(); | 155 Widget::Hide(); |
176 } | 156 } |
177 | 157 |
178 void KeyboardManager::OnBrowserAdded(const Browser* browser) { | |
179 browser->tabstrip_model()->AddObserver(this); | |
180 } | |
181 | |
182 void KeyboardManager::OnBrowserRemoved(const Browser* browser) { | |
183 browser->tabstrip_model()->RemoveObserver(this); | |
184 } | |
185 | |
186 bool KeyboardManager::OnMessageReceived(const IPC::Message& message) { | 158 bool KeyboardManager::OnMessageReceived(const IPC::Message& message) { |
187 bool handled = true; | 159 bool handled = true; |
188 IPC_BEGIN_MESSAGE_MAP(KeyboardManager, message) | 160 IPC_BEGIN_MESSAGE_MAP(KeyboardManager, message) |
189 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) | 161 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) |
190 IPC_MESSAGE_UNHANDLED(handled = false) | 162 IPC_MESSAGE_UNHANDLED(handled = false) |
191 IPC_END_MESSAGE_MAP() | 163 IPC_END_MESSAGE_MAP() |
192 return handled; | 164 return handled; |
193 } | 165 } |
194 | 166 |
195 void KeyboardManager::OnRequest( | 167 void KeyboardManager::OnRequest( |
196 const ExtensionHostMsg_Request_Params& request) { | 168 const ExtensionHostMsg_Request_Params& request) { |
197 extension_dispatcher_.Dispatch(request, | 169 extension_dispatcher_.Dispatch(request, |
198 dom_view_->tab_contents()->render_view_host()); | 170 dom_view_->tab_contents()->render_view_host()); |
199 } | 171 } |
200 | 172 |
201 void KeyboardManager::ActiveTabChanged(TabContentsWrapper* old_contents, | 173 void KeyboardManager::TextInputTypeChanged(ui::TextInputType type, |
202 TabContentsWrapper* new_contents, | 174 views::Widget *widget) { |
203 int index, | 175 // Send onTextInputTypeChanged event to keyboard extension. |
204 bool user_gesture) { | 176 ListValue args; |
205 TabContents* contents = new_contents->tab_contents(); | 177 switch (type) { |
206 if (!TabContentsCanAffectKeyboard(contents)) | 178 case ui::TEXT_INPUT_TYPE_NONE: { |
207 return; | 179 args.Append(Value::CreateStringValue("none")); |
| 180 break; |
| 181 } |
| 182 case ui::TEXT_INPUT_TYPE_TEXT: { |
| 183 args.Append(Value::CreateStringValue("text")); |
| 184 break; |
| 185 } |
| 186 case ui::TEXT_INPUT_TYPE_PASSWORD: { |
| 187 args.Append(Value::CreateStringValue("password")); |
| 188 break; |
| 189 } |
| 190 case ui::TEXT_INPUT_TYPE_SEARCH: { |
| 191 args.Append(Value::CreateStringValue("search")); |
| 192 break; |
| 193 } |
| 194 case ui::TEXT_INPUT_TYPE_EMAIL: { |
| 195 args.Append(Value::CreateStringValue("email")); |
| 196 break; |
| 197 } |
| 198 case ui::TEXT_INPUT_TYPE_NUMBER: { |
| 199 args.Append(Value::CreateStringValue("number")); |
| 200 break; |
| 201 } |
| 202 case ui::TEXT_INPUT_TYPE_TELEPHONE: { |
| 203 args.Append(Value::CreateStringValue("tel")); |
| 204 break; |
| 205 } |
| 206 case ui::TEXT_INPUT_TYPE_URL: { |
| 207 args.Append(Value::CreateStringValue("url")); |
| 208 break; |
| 209 } |
| 210 default: { |
| 211 NOTREACHED(); |
| 212 args.Append(Value::CreateStringValue("none")); |
| 213 break; |
| 214 } |
| 215 } |
208 | 216 |
209 // If the tab contents does not have the focus, then it should not affect the | 217 std::string json_args; |
210 // keyboard visibility. | 218 base::JSONWriter::Write(&args, false, &json_args); |
211 views::View* view = static_cast<TabContentsViewTouch*>(contents->view()); | |
212 views::FocusManager* fmanager = view ? view->GetFocusManager() : NULL; | |
213 if (!fmanager || !view->Contains(fmanager->GetFocusedView())) | |
214 return; | |
215 | 219 |
216 bool* editable = GetFocusedStateAccessor()->GetProperty( | 220 Profile* profile = |
217 contents->property_bag()); | 221 Profile::FromBrowserContext(dom_view_->tab_contents()->browser_context()); |
218 if (editable && *editable) | 222 profile->GetExtensionEventRouter()->DispatchEventToRenderers( |
219 ShowKeyboardForWidget(view->GetWidget()); | 223 kOnTextInputTypeChanged, json_args, NULL, GURL()); |
| 224 |
| 225 if (type == ui::TEXT_INPUT_TYPE_NONE) |
| 226 Hide(); |
220 else | 227 else |
221 Hide(); | 228 ShowKeyboardForWidget(widget); |
222 } | 229 } |
223 | 230 |
224 Browser* KeyboardManager::GetBrowser() { | 231 Browser* KeyboardManager::GetBrowser() { |
225 // TODO(sad): Find a better way. Perhaps just return NULL, and fix | 232 // TODO(sad): Find a better way. Perhaps just return NULL, and fix |
226 // SendKeyboardEventInputFunction::GetTopLevelWidget to somehow interact with | 233 // SendKeyboardEventInputFunction::GetTopLevelWidget to somehow interact with |
227 // the WM to find the top level widget? | 234 // the WM to find the top level widget? |
228 return BrowserList::GetLastActive(); | 235 return BrowserList::GetLastActive(); |
229 } | 236 } |
230 | 237 |
231 gfx::NativeView KeyboardManager::GetNativeViewOfHost() { | 238 gfx::NativeView KeyboardManager::GetNativeViewOfHost() { |
(...skipping 12 matching lines...) Expand all Loading... |
244 const GURL& url = virtual_keyboard.GetURLForLayout(virtual_keyboard_layout); | 251 const GURL& url = virtual_keyboard.GetURLForLayout(virtual_keyboard_layout); |
245 dom_view_->LoadURL(url); | 252 dom_view_->LoadURL(url); |
246 VLOG(1) << "VirtualKeyboardChanged: Switched to " << url.spec(); | 253 VLOG(1) << "VirtualKeyboardChanged: Switched to " << url.spec(); |
247 } | 254 } |
248 #endif | 255 #endif |
249 | 256 |
250 void KeyboardManager::Observe(int type, | 257 void KeyboardManager::Observe(int type, |
251 const NotificationSource& source, | 258 const NotificationSource& source, |
252 const NotificationDetails& details) { | 259 const NotificationDetails& details) { |
253 switch (type) { | 260 switch (type) { |
254 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { | |
255 // When a navigation happens, we want to hide the keyboard if the focus is | |
256 // in the web-page. Otherwise, the keyboard visibility should not change. | |
257 NavigationController* controller = | |
258 Source<NavigationController>(source).ptr(); | |
259 TabContents* tab_contents = controller->tab_contents(); | |
260 GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(), | |
261 false); | |
262 if (!TabContentsCanAffectKeyboard(tab_contents)) | |
263 break; | |
264 | |
265 TabContentsViewTouch* view = | |
266 static_cast<TabContentsViewTouch*>(tab_contents->view()); | |
267 views::FocusManager* fmanager = view->GetFocusManager(); | |
268 views::View* focused = fmanager ? fmanager->GetFocusedView() : NULL; | |
269 views::TextInputClient* input = | |
270 focused ? focused->GetTextInputClient() : NULL; | |
271 // Show the keyboard if the focused view supports text-input. | |
272 if (input && input->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) | |
273 ShowKeyboardForWidget(focused->GetWidget()); | |
274 else | |
275 Hide(); | |
276 break; | |
277 } | |
278 | |
279 case content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE: { | |
280 // If the focus in the page moved to an editable field, then the keyboard | |
281 // should be visible, otherwise not. | |
282 TabContents* tab_contents = Source<TabContents>(source).ptr(); | |
283 const bool editable = *Details<const bool>(details).ptr(); | |
284 GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(), | |
285 editable); | |
286 if (!TabContentsCanAffectKeyboard(tab_contents)) | |
287 break; | |
288 | |
289 if (editable) { | |
290 TabContentsViewTouch* view = | |
291 static_cast<TabContentsViewTouch*>(tab_contents->view()); | |
292 ShowKeyboardForWidget(view->GetWidget()); | |
293 } else { | |
294 Hide(); | |
295 } | |
296 | |
297 break; | |
298 } | |
299 | |
300 case content::NOTIFICATION_TAB_CONTENTS_DESTROYED: { | |
301 // Tab content was destroyed. Forget everything about it. | |
302 GetFocusedStateAccessor()->DeleteProperty( | |
303 Source<TabContents>(source).ptr()->property_bag()); | |
304 break; | |
305 } | |
306 | |
307 case chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED: { | 261 case chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED: { |
308 // The keyboard is hiding itself. | |
309 Browser* browser = BrowserList::GetLastActive(); | |
310 if (browser) { | |
311 TabContents* tab_contents = browser->GetSelectedTabContents(); | |
312 if (tab_contents) { | |
313 GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(), | |
314 false); | |
315 } | |
316 } | |
317 | |
318 Hide(); | 262 Hide(); |
319 break; | 263 break; |
320 } | 264 } |
321 | 265 |
322 case chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED: { | 266 case chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED: { |
323 // The keyboard is resizing itself. | 267 // The keyboard is resizing itself. |
324 | 268 |
325 // TODO(penghuang) Allow extension conrtol the virtual keyboard directly | 269 // TODO(penghuang) Allow extension conrtol the virtual keyboard directly |
326 // instead of using Notification. | 270 // instead of using Notification. |
327 int height = *Details<int>(details).ptr(); | 271 int height = *Details<int>(details).ptr(); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 | 318 |
375 void KeyboardManager::OnWidgetActivationChanged(Widget* widget, bool active) { | 319 void KeyboardManager::OnWidgetActivationChanged(Widget* widget, bool active) { |
376 if (target_ == widget && !active) | 320 if (target_ == widget && !active) |
377 SetTarget(NULL); | 321 SetTarget(NULL); |
378 } | 322 } |
379 | 323 |
380 // static | 324 // static |
381 KeyboardManager* KeyboardManager::GetInstance() { | 325 KeyboardManager* KeyboardManager::GetInstance() { |
382 return Singleton<KeyboardManager>::get(); | 326 return Singleton<KeyboardManager>::get(); |
383 } | 327 } |
OLD | NEW |