Chromium Code Reviews| 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, |
|
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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |