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

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

Issue 7553016: Use text input type to control visibility of virtual keyboard (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Fix reiview issues Created 9 years, 4 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 | Annotate | Revision Log
OLDNEW
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
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,
bryeung 2011/08/03 22:22:04 Do we still need this? Won't all editable element
Peng 2011/08/04 19:47:53 I am not sure if it can be removed safely. Add maz
sadrul 2011/08/04 20:07:56 I believe this is still necessary for this case: (
mazda 2011/08/05 01:59:28 Yes, it is necessary. TextInputType change notific
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() {
96 views::TextInputTypeTracker::GetInstance()->RemoveTextInputTypeObserver(this);
117 #if defined(OS_CHROMEOS) 97 #if defined(OS_CHROMEOS)
118 chromeos::input_method::InputMethodManager* manager = 98 chromeos::input_method::InputMethodManager* manager =
119 chromeos::input_method::InputMethodManager::GetInstance(); 99 chromeos::input_method::InputMethodManager::GetInstance();
120 manager->RemoveVirtualKeyboardObserver(this); 100 manager->RemoveVirtualKeyboardObserver(this);
121 #endif 101 #endif
122 // TODO(sad): Do anything else? 102 // TODO(sad): Do anything else?
123 } 103 }
124 104
125 void KeyboardManager::ShowKeyboardForWidget(views::Widget* widget) { 105 void KeyboardManager::ShowKeyboardForWidget(views::Widget* widget) {
126 target_ = widget; 106 target_ = widget;
(...skipping 28 matching lines...) Expand all
155 void KeyboardManager::AnimationProgressed(const ui::Animation* animation) { 135 void KeyboardManager::AnimationProgressed(const ui::Animation* animation) {
156 GetRootView()->SetTransform( 136 GetRootView()->SetTransform(
157 transform_->Interpolate(animation_->GetCurrentValue())); 137 transform_->Interpolate(animation_->GetCurrentValue()));
158 } 138 }
159 139
160 void KeyboardManager::AnimationEnded(const ui::Animation* animation) { 140 void KeyboardManager::AnimationEnded(const ui::Animation* animation) {
161 if (animation_->GetCurrentValue() < 0.01) 141 if (animation_->GetCurrentValue() < 0.01)
162 Widget::Hide(); 142 Widget::Hide();
163 } 143 }
164 144
165 void KeyboardManager::OnBrowserAdded(const Browser* browser) {
166 browser->tabstrip_model()->AddObserver(this);
167 }
168
169 void KeyboardManager::OnBrowserRemoved(const Browser* browser) {
170 browser->tabstrip_model()->RemoveObserver(this);
171 }
172
173 bool KeyboardManager::OnMessageReceived(const IPC::Message& message) { 145 bool KeyboardManager::OnMessageReceived(const IPC::Message& message) {
174 bool handled = true; 146 bool handled = true;
175 IPC_BEGIN_MESSAGE_MAP(KeyboardManager, message) 147 IPC_BEGIN_MESSAGE_MAP(KeyboardManager, message)
176 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) 148 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
177 IPC_MESSAGE_UNHANDLED(handled = false) 149 IPC_MESSAGE_UNHANDLED(handled = false)
178 IPC_END_MESSAGE_MAP() 150 IPC_END_MESSAGE_MAP()
179 return handled; 151 return handled;
180 } 152 }
181 153
182 void KeyboardManager::OnRequest( 154 void KeyboardManager::OnRequest(
183 const ExtensionHostMsg_Request_Params& request) { 155 const ExtensionHostMsg_Request_Params& request) {
184 extension_dispatcher_.Dispatch(request, 156 extension_dispatcher_.Dispatch(request,
185 dom_view_->tab_contents()->render_view_host()); 157 dom_view_->tab_contents()->render_view_host());
186 } 158 }
187 159
188 void KeyboardManager::ActiveTabChanged(TabContentsWrapper* old_contents, 160 void KeyboardManager::TextInputTypeChanged(ui::TextInputType type,
189 TabContentsWrapper* new_contents, 161 views::Widget *widget)
190 int index, 162 {
191 bool user_gesture) { 163 // Send onTextInputTypeChanged event to keyboard extension.
192 TabContents* contents = new_contents->tab_contents(); 164 ListValue args;
bryeung 2011/08/03 22:22:04 Why a ListValue instead of a StringValue? Looks l
Peng 2011/08/04 19:47:53 ListValue is for creating arguments for onTextInpu
193 if (!TabContentsCanAffectKeyboard(contents)) 165 switch (type) {
194 return; 166 case ui::TEXT_INPUT_TYPE_NONE:
bryeung 2011/08/03 22:22:04 Is this the right indentation? I was expecting ev
Peng 2011/08/04 19:47:53 Done.
167 args.Append(Value::CreateStringValue("none"));
168 break;
169 case ui::TEXT_INPUT_TYPE_TEXT:
170 args.Append(Value::CreateStringValue("text"));
171 break;
172 case ui::TEXT_INPUT_TYPE_PASSWORD:
173 args.Append(Value::CreateStringValue("password"));
174 break;
175 case ui::TEXT_INPUT_TYPE_SEARCH:
176 args.Append(Value::CreateStringValue("search"));
177 break;
178 case ui::TEXT_INPUT_TYPE_EMAIL:
179 args.Append(Value::CreateStringValue("email"));
180 break;
181 case ui::TEXT_INPUT_TYPE_NUMBER:
182 args.Append(Value::CreateStringValue("number"));
183 break;
184 case ui::TEXT_INPUT_TYPE_TELEPHONE:
185 args.Append(Value::CreateStringValue("tel"));
186 break;
187 case ui::TEXT_INPUT_TYPE_URL:
188 args.Append(Value::CreateStringValue("url"));
189 break;
190 default:
191 args.Append(Value::CreateStringValue("none"));
192 break;
193 }
195 194
196 // If the tab contents does not have the focus, then it should not affect the 195 std::string json_args;
197 // keyboard visibility. 196 base::JSONWriter::Write(&args, false, &json_args);
198 views::View* view = static_cast<TabContentsViewTouch*>(contents->view());
199 views::FocusManager* fmanager = view ? view->GetFocusManager() : NULL;
200 if (!fmanager || !view->Contains(fmanager->GetFocusedView()))
201 return;
202 197
203 bool* editable = GetFocusedStateAccessor()->GetProperty( 198 Profile* profile =
204 contents->property_bag()); 199 Profile::FromBrowserContext(dom_view_->tab_contents()->browser_context());
205 if (editable && *editable) 200 profile->GetExtensionEventRouter()->DispatchEventToRenderers(
206 ShowKeyboardForWidget(view->GetWidget()); 201 kOnTextInputTypeChanged, json_args, NULL, GURL());
sadrul 2011/08/03 23:01:14 Does this send the event to all extension renderer
Peng 2011/08/04 19:47:53 It will send the event to all extensions which lis
202
203 if (type == ui::TEXT_INPUT_TYPE_NONE)
204 Hide();
207 else 205 else
208 Hide(); 206 ShowKeyboardForWidget(widget);
209 } 207 }
210 208
211 Browser* KeyboardManager::GetBrowser() { 209 Browser* KeyboardManager::GetBrowser() {
212 // TODO(sad): Find a better way. Perhaps just return NULL, and fix 210 // TODO(sad): Find a better way. Perhaps just return NULL, and fix
213 // SendKeyboardEventInputFunction::GetTopLevelWidget to somehow interact with 211 // SendKeyboardEventInputFunction::GetTopLevelWidget to somehow interact with
214 // the WM to find the top level widget? 212 // the WM to find the top level widget?
215 return BrowserList::GetLastActive(); 213 return BrowserList::GetLastActive();
216 } 214 }
217 215
218 gfx::NativeView KeyboardManager::GetNativeViewOfHost() { 216 gfx::NativeView KeyboardManager::GetNativeViewOfHost() {
(...skipping 12 matching lines...) Expand all
231 const GURL& url = virtual_keyboard.GetURLForLayout(virtual_keyboard_layout); 229 const GURL& url = virtual_keyboard.GetURLForLayout(virtual_keyboard_layout);
232 dom_view_->LoadURL(url); 230 dom_view_->LoadURL(url);
233 VLOG(1) << "VirtualKeyboardChanged: Switched to " << url.spec(); 231 VLOG(1) << "VirtualKeyboardChanged: Switched to " << url.spec();
234 } 232 }
235 #endif 233 #endif
236 234
237 void KeyboardManager::Observe(int type, 235 void KeyboardManager::Observe(int type,
238 const NotificationSource& source, 236 const NotificationSource& source,
239 const NotificationDetails& details) { 237 const NotificationDetails& details) {
240 switch (type) { 238 switch (type) {
241 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
242 // When a navigation happens, we want to hide the keyboard if the focus is
243 // in the web-page. Otherwise, the keyboard visibility should not change.
244 NavigationController* controller =
245 Source<NavigationController>(source).ptr();
246 TabContents* tab_contents = controller->tab_contents();
247 GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(),
248 false);
249 if (!TabContentsCanAffectKeyboard(tab_contents))
250 break;
251
252 TabContentsViewTouch* view =
253 static_cast<TabContentsViewTouch*>(tab_contents->view());
254 views::View* focused = view->GetFocusManager()->GetFocusedView();
255 views::TextInputClient* input =
256 focused ? focused->GetTextInputClient() : NULL;
257 // Show the keyboard if the focused view supports text-input.
258 if (input && input->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
259 ShowKeyboardForWidget(focused->GetWidget());
260 else
261 Hide();
262 break;
263 }
264
265 case content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE: {
266 // If the focus in the page moved to an editable field, then the keyboard
267 // should be visible, otherwise not.
268 TabContents* tab_contents = Source<TabContents>(source).ptr();
269 const bool editable = *Details<const bool>(details).ptr();
270 GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(),
271 editable);
272 if (!TabContentsCanAffectKeyboard(tab_contents))
273 break;
274
275 if (editable) {
276 TabContentsViewTouch* view =
277 static_cast<TabContentsViewTouch*>(tab_contents->view());
278 ShowKeyboardForWidget(view->GetWidget());
279 } else {
280 Hide();
281 }
282
283 break;
284 }
285
286 case content::NOTIFICATION_TAB_CONTENTS_DESTROYED: {
287 // Tab content was destroyed. Forget everything about it.
288 GetFocusedStateAccessor()->DeleteProperty(
289 Source<TabContents>(source).ptr()->property_bag());
290 break;
291 }
292
293 case chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED: { 239 case chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED: {
294 // The keyboard is hiding itself.
295 Browser* browser = BrowserList::GetLastActive();
296 if (browser) {
297 TabContents* tab_contents = browser->GetSelectedTabContents();
298 if (tab_contents) {
299 GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(),
300 false);
301 }
302 }
303
304 Hide(); 240 Hide();
305 break; 241 break;
306 } 242 }
307 243
308 case chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED: { 244 case chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED: {
309 // The keyboard is resizing itself. 245 // The keyboard is resizing itself.
310 246
311 // TODO(penghuang) Allow extension conrtol the virtual keyboard directly 247 // TODO(penghuang) Allow extension conrtol the virtual keyboard directly
312 // instead of using Notification. 248 // instead of using Notification.
313 int height = *Details<int>(details).ptr(); 249 int height = *Details<int>(details).ptr();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 281
346 default: 282 default:
347 NOTREACHED(); 283 NOTREACHED();
348 } 284 }
349 } 285 }
350 286
351 // static 287 // static
352 KeyboardManager* KeyboardManager::GetInstance() { 288 KeyboardManager* KeyboardManager::GetInstance() {
353 return Singleton<KeyboardManager>::get(); 289 return Singleton<KeyboardManager>::get();
354 } 290 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698