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

Side by Side Diff: chrome/browser/ui/touch/frame/touch_browser_frame_view.cc

Issue 7302015: A keyboard widget that manages itself (the animation and all that). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge with trunk 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/frame/touch_browser_frame_view.h" 5 #include "chrome/browser/ui/touch/frame/touch_browser_frame_view.h"
6 6
7 #include "chrome/browser/profiles/profile.h" 7 #include "chrome/browser/ui/touch/keyboard/keyboard_manager.h"
8 #include "chrome/browser/renderer_host/render_widget_host_view_views.h" 8 #include "ui/base/ime/text_input_type.h"
9 #include "chrome/browser/tabs/tab_strip_model.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
12 #include "chrome/browser/ui/touch/frame/keyboard_container_view.h"
13 #include "chrome/browser/ui/views/frame/browser_view.h"
14 #include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h"
15 #include "chrome/common/chrome_notification_types.h"
16 #include "content/browser/renderer_host/render_view_host.h"
17 #include "content/browser/tab_contents/navigation_controller.h"
18 #include "content/browser/tab_contents/tab_contents.h"
19 #include "content/browser/tab_contents/tab_contents_view.h"
20 #include "content/common/content_notification_types.h"
21 #include "content/common/notification_service.h"
22 #include "content/common/view_messages.h"
23 #include "ui/base/animation/slide_animation.h"
24 #include "ui/gfx/rect.h"
25 #include "ui/gfx/transform.h"
26 #include "views/controls/button/image_button.h" 9 #include "views/controls/button/image_button.h"
27 #include "views/controls/textfield/textfield.h" 10 #include "views/controls/textfield/textfield.h"
28 #include "views/focus/focus_manager.h" 11 #include "views/focus/focus_manager.h"
12 #include "views/ime/text_input_client.h"
29 #include "views/window/hit_test.h" 13 #include "views/window/hit_test.h"
30 14
31 #if defined(OS_CHROMEOS)
32 #include "chrome/browser/chromeos/input_method/virtual_keyboard_selector.h"
33 #endif
34
35 namespace {
36
37 const int kDefaultKeyboardHeight = 300;
38 const int kKeyboardSlideDuration = 300; // In milliseconds
39
40 PropertyAccessor<bool>* GetFocusedStateAccessor() {
41 static PropertyAccessor<bool> state;
42 return &state;
43 }
44
45 bool TabContentsHasFocus(const TabContents* contents) {
46 views::View* view = static_cast<TabContentsViewTouch*>(contents->view());
47 return view->Contains(view->GetFocusManager()->GetFocusedView());
48 }
49
50 } // namespace
51
52 // static 15 // static
53 const char TouchBrowserFrameView::kViewClassName[] = 16 const char TouchBrowserFrameView::kViewClassName[] =
54 "browser/ui/touch/frame/TouchBrowserFrameView"; 17 "browser/ui/touch/frame/TouchBrowserFrameView";
55 18
56 /////////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////////
57 // TouchBrowserFrameView, public: 20 // TouchBrowserFrameView, public:
58 21
59 TouchBrowserFrameView::TouchBrowserFrameView(BrowserFrame* frame, 22 TouchBrowserFrameView::TouchBrowserFrameView(BrowserFrame* frame,
60 BrowserView* browser_view) 23 BrowserView* browser_view)
61 : OpaqueBrowserFrameView(frame, browser_view), 24 : OpaqueBrowserFrameView(frame, browser_view),
62 keyboard_showing_(false), 25 focus_listener_added_(false) {
63 keyboard_height_(kDefaultKeyboardHeight), 26 // Make sure the singleton KeyboardManager object is initialized.
64 focus_listener_added_(false), 27 KeyboardManager::GetInstance();
65 keyboard_(NULL) {
66 registrar_.Add(this,
67 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
68 NotificationService::AllSources());
69 registrar_.Add(this,
70 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
71 NotificationService::AllSources());
72 registrar_.Add(this,
73 content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
74 NotificationService::AllSources());
75 registrar_.Add(this,
76 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED,
77 NotificationService::AllSources());
78 registrar_.Add(this,
79 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED,
80 NotificationService::AllSources());
81 registrar_.Add(this,
82 chrome::NOTIFICATION_EDITABLE_ELEMENT_TOUCHED,
83 NotificationService::AllSources());
84
85 browser_view->browser()->tabstrip_model()->AddObserver(this);
86
87 animation_.reset(new ui::SlideAnimation(this));
88 animation_->SetTweenType(ui::Tween::LINEAR);
89 animation_->SetSlideDuration(kKeyboardSlideDuration);
90
91 #if defined(OS_CHROMEOS)
92 chromeos::input_method::InputMethodManager* manager =
93 chromeos::input_method::InputMethodManager::GetInstance();
94 manager->AddVirtualKeyboardObserver(this);
95 #endif
96 } 28 }
97 29
98 TouchBrowserFrameView::~TouchBrowserFrameView() { 30 TouchBrowserFrameView::~TouchBrowserFrameView() {
99 browser_view()->browser()->tabstrip_model()->RemoveObserver(this);
100 } 31 }
101 32
102 int TouchBrowserFrameView::NonClientHitTest(const gfx::Point& point) { 33 ///////////////////////////////////////////////////////////////////////////////
103 if (keyboard_ && keyboard_->GetMirroredBounds().Contains(point)) 34 // TouchBrowserFrameView, private:
104 return HTCLIENT; 35
105 return OpaqueBrowserFrameView::NonClientHitTest(point); 36 void TouchBrowserFrameView::FocusWillChange(views::View* focused_before,
37 views::View* focused_now) {
38 views::Widget* widget = focused_now ? focused_now->GetWidget() : NULL;
39 if (!widget || !widget->IsActive())
40 return;
41
42 views::TextInputClient* input =
43 focused_now ? focused_now->GetTextInputClient() : NULL;
44 // Show the keyboard if the focused view supports text-input.
45 KeyboardManager* keyboard = KeyboardManager::GetInstance();
46 if (input && input->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
47 keyboard->ShowKeyboardForWidget(focused_now->GetWidget());
48 else
49 keyboard->Hide();
106 } 50 }
107 51
108 std::string TouchBrowserFrameView::GetClassName() const { 52 std::string TouchBrowserFrameView::GetClassName() const {
109 return kViewClassName; 53 return kViewClassName;
110 } 54 }
111 55
112 void TouchBrowserFrameView::Layout() {
113 OpaqueBrowserFrameView::Layout();
114
115 if (!keyboard_)
116 return;
117
118 keyboard_->SetVisible(keyboard_showing_ || animation_->is_animating());
119 gfx::Rect bounds = GetBoundsForReservedArea();
120 if (animation_->is_animating() && !keyboard_showing_) {
121 // The keyboard is in the process of hiding. So pretend it still has the
122 // same bounds as when the keyboard is visible. But
123 // |GetBoundsForReservedArea| should not take this into account so that the
124 // render view gets the entire area to relayout itself.
125 bounds.set_y(bounds.y() - keyboard_height_);
126 bounds.set_height(keyboard_height_);
127 }
128 keyboard_->SetBoundsRect(bounds);
129 }
130
131 void TouchBrowserFrameView::FocusWillChange(views::View* focused_before,
132 views::View* focused_now) {
133 VirtualKeyboardType before = DecideKeyboardStateForView(focused_before);
134 VirtualKeyboardType now = DecideKeyboardStateForView(focused_now);
135 if (before != now) {
136 // TODO(varunjain): support other types of keyboard.
137 UpdateKeyboardAndLayout(now == GENERIC);
138 }
139 }
140
141 ///////////////////////////////////////////////////////////////////////////////
142 // TouchBrowserFrameView, protected:
143
144 int TouchBrowserFrameView::GetReservedHeight() const {
145 return keyboard_showing_ ? keyboard_height_ : 0;
146 }
147
148 void TouchBrowserFrameView::ViewHierarchyChanged(bool is_add, 56 void TouchBrowserFrameView::ViewHierarchyChanged(bool is_add,
149 View* parent, 57 View* parent,
150 View* child) { 58 View* child) {
151 OpaqueBrowserFrameView::ViewHierarchyChanged(is_add, parent, child); 59 OpaqueBrowserFrameView::ViewHierarchyChanged(is_add, parent, child);
152 if (!GetFocusManager()) 60 if (!GetFocusManager())
153 return; 61 return;
154 62
155 if (is_add && !focus_listener_added_) { 63 if (is_add && !focus_listener_added_) {
156 // Add focus listener when this view is added to the hierarchy. 64 // Add focus listener when this view is added to the hierarchy.
157 GetFocusManager()->AddFocusChangeListener(this); 65 GetFocusManager()->AddFocusChangeListener(this);
158 focus_listener_added_ = true; 66 focus_listener_added_ = true;
159 } else if (!is_add && focus_listener_added_) { 67 } else if (!is_add && focus_listener_added_) {
160 // Remove focus listener when this view is removed from the hierarchy. 68 // Remove focus listener when this view is removed from the hierarchy.
161 GetFocusManager()->RemoveFocusChangeListener(this); 69 GetFocusManager()->RemoveFocusChangeListener(this);
162 focus_listener_added_ = false; 70 focus_listener_added_ = false;
163 } 71 }
164 } 72 }
165 73
166 ///////////////////////////////////////////////////////////////////////////////
167 // TouchBrowserFrameView, private:
168
169 void TouchBrowserFrameView::InitVirtualKeyboard() {
170 if (keyboard_)
171 return;
172
173 Profile* keyboard_profile = browser_view()->browser()->profile();
174 DCHECK(keyboard_profile) << "Profile required for virtual keyboard.";
175
176 keyboard_ = new KeyboardContainerView(keyboard_profile,
177 browser_view()->browser(),
178 url_);
179 keyboard_->SetVisible(false);
180 AddChildView(keyboard_);
181 }
182
183 void TouchBrowserFrameView::UpdateKeyboardAndLayout(bool should_show_keyboard) {
184 if (should_show_keyboard)
185 InitVirtualKeyboard();
186
187 if (should_show_keyboard == keyboard_showing_)
188 return;
189
190 DCHECK(keyboard_);
191
192 keyboard_showing_ = should_show_keyboard;
193 if (keyboard_showing_) {
194 // We don't re-layout the client view until the animation ends (see
195 // AnimationEnded below) because we want the client view to occupy the
196 // entire height during the animation. It is necessary to reset the
197 // transform for the keyboard first so that the contents are sized properly
198 // when layout, and then start the animation.
199 ui::Transform reset;
200 keyboard_->SetTransform(reset);
201 Layout();
202
203 animation_->Show();
204 } else {
205 animation_->Hide();
206
207 browser_view()->set_clip_y(ui::Tween::ValueBetween(
208 animation_->GetCurrentValue(), 0, keyboard_height_));
209 parent()->Layout();
210 }
211 }
212
213 TouchBrowserFrameView::VirtualKeyboardType
214 TouchBrowserFrameView::DecideKeyboardStateForView(views::View* view) {
215 if (!view)
216 return NONE;
217
218 std::string cname = view->GetClassName();
219 if (cname == views::Textfield::kViewClassName) {
220 return GENERIC;
221 } else if (cname == RenderWidgetHostViewViews::kViewClassName) {
222 TabContents* contents = browser_view()->browser()->GetSelectedTabContents();
223 bool* editable = contents ? GetFocusedStateAccessor()->GetProperty(
224 contents->property_bag()) : NULL;
225 if (editable && *editable)
226 return GENERIC;
227 }
228 return NONE;
229 }
230
231 bool TouchBrowserFrameView::HitTest(const gfx::Point& point) const { 74 bool TouchBrowserFrameView::HitTest(const gfx::Point& point) const {
232 if (OpaqueBrowserFrameView::HitTest(point)) 75 if (OpaqueBrowserFrameView::HitTest(point))
233 return true; 76 return true;
234 77
235 if (close_button()->IsVisible() && 78 if (close_button()->IsVisible() &&
236 close_button()->GetMirroredBounds().Contains(point)) 79 close_button()->GetMirroredBounds().Contains(point))
237 return true; 80 return true;
238 if (restore_button()->IsVisible() && 81 if (restore_button()->IsVisible() &&
239 restore_button()->GetMirroredBounds().Contains(point)) 82 restore_button()->GetMirroredBounds().Contains(point))
240 return true; 83 return true;
241 if (maximize_button()->IsVisible() && 84 if (maximize_button()->IsVisible() &&
242 maximize_button()->GetMirroredBounds().Contains(point)) 85 maximize_button()->GetMirroredBounds().Contains(point))
243 return true; 86 return true;
244 if (minimize_button()->IsVisible() && 87 if (minimize_button()->IsVisible() &&
245 minimize_button()->GetMirroredBounds().Contains(point)) 88 minimize_button()->GetMirroredBounds().Contains(point))
246 return true; 89 return true;
247 90
248 return false; 91 return false;
249 } 92 }
250
251 void TouchBrowserFrameView::ActiveTabChanged(TabContentsWrapper* old_contents,
252 TabContentsWrapper* new_contents,
253 int index,
254 bool user_gesture) {
255 TabContents* contents = new_contents->tab_contents();
256 if (!TabContentsHasFocus(contents))
257 return;
258
259 bool* editable = GetFocusedStateAccessor()->GetProperty(
260 contents->property_bag());
261 UpdateKeyboardAndLayout(editable ? *editable : false);
262 }
263
264 void TouchBrowserFrameView::TabStripEmpty() {
265 if (animation_->is_animating()) {
266 // Reset the delegate so the AnimationEnded callback doesn't trigger.
267 animation_->set_delegate(NULL);
268 animation_->Stop();
269 }
270 }
271
272 void TouchBrowserFrameView::Observe(int type,
273 const NotificationSource& source,
274 const NotificationDetails& details) {
275 Browser* browser = browser_view()->browser();
276 if (type == content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE) {
277 // Only modify the keyboard state if the currently active tab sent the
278 // notification.
279 const TabContents* current_tab = browser->GetSelectedTabContents();
280 TabContents* source_tab = Source<TabContents>(source).ptr();
281 const bool editable = *Details<const bool>(details).ptr();
282
283 if (current_tab == source_tab && TabContentsHasFocus(source_tab))
284 UpdateKeyboardAndLayout(editable);
285
286 // Save the state of the focused field so that the keyboard visibility
287 // can be determined after tab switching.
288 GetFocusedStateAccessor()->SetProperty(
289 source_tab->property_bag(), editable);
290 } else if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) {
291 NavigationController* controller =
292 Source<NavigationController>(source).ptr();
293 Browser* source_browser = Browser::GetBrowserForController(
294 controller, NULL);
295
296 // If the Browser for the keyboard has navigated, re-evaluate the visibility
297 // of the keyboard.
298 TouchBrowserFrameView::VirtualKeyboardType keyboard_type = NONE;
299 views::View* view = GetFocusManager()->GetFocusedView();
300 if (view) {
301 if (view->GetClassName() == views::Textfield::kViewClassName)
302 keyboard_type = GENERIC;
303 if (view->GetClassName() == RenderWidgetHostViewViews::kViewClassName) {
304 // Reset the state of the focused field in the current tab.
305 GetFocusedStateAccessor()->SetProperty(
306 controller->tab_contents()->property_bag(), false);
307 }
308 }
309 if (source_browser == browser)
310 UpdateKeyboardAndLayout(keyboard_type == GENERIC);
311 } else if (type == content::NOTIFICATION_TAB_CONTENTS_DESTROYED) {
312 GetFocusedStateAccessor()->DeleteProperty(
313 Source<TabContents>(source).ptr()->property_bag());
314 } else if (type == chrome::NOTIFICATION_PREF_CHANGED) {
315 OpaqueBrowserFrameView::Observe(type, source, details);
316 } else if (type == chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED) {
317 TabContents* tab_contents =
318 browser_view()->browser()->GetSelectedTabContents();
319 if (tab_contents) {
320 GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(),
321 false);
322 }
323 UpdateKeyboardAndLayout(false);
324 } else if (type == chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED) {
325 // TODO(penghuang) Allow extension conrtol the virtual keyboard directly
326 // instead of using Notification.
327 int height = *reinterpret_cast<int*>(details.map_key());
328 if (height != keyboard_height_) {
329 DCHECK_GE(height, 0) << "Height of the keyboard is less than 0.";
330 DCHECK_LE(height, View::height()) << "Height of the keyboard is greater "
331 "than the height of frame view.";
332 keyboard_height_ = height;
333 parent()->Layout();
334 }
335 } else if (type == chrome::NOTIFICATION_EDITABLE_ELEMENT_TOUCHED) {
336 UpdateKeyboardAndLayout(true);
337 }
338 }
339
340 ///////////////////////////////////////////////////////////////////////////////
341 // ui::AnimationDelegate implementation
342 void TouchBrowserFrameView::AnimationProgressed(const ui::Animation* anim) {
343 ui::Transform transform;
344 transform.SetTranslateY(
345 ui::Tween::ValueBetween(anim->GetCurrentValue(), keyboard_height_, 0));
346 keyboard_->SetTransform(transform);
347 browser_view()->set_clip_y(
348 ui::Tween::ValueBetween(anim->GetCurrentValue(), 0, keyboard_height_));
349 SchedulePaint();
350 }
351
352 void TouchBrowserFrameView::AnimationEnded(const ui::Animation* animation) {
353 browser_view()->set_clip_y(0);
354 if (keyboard_showing_) {
355 // Because the NonClientFrameView is a sibling of the ClientView, we rely on
356 // the parent to resize the ClientView instead of resizing it directly.
357 parent()->Layout();
358
359 // The keyboard that pops up may end up hiding the text entry. So make sure
360 // the renderer scrolls when necessary to keep the textfield visible.
361 RenderViewHost* host =
362 browser_view()->browser()->GetSelectedTabContents()->render_view_host();
363 host->Send(new ViewMsg_ScrollFocusedEditableNodeIntoView(
364 host->routing_id()));
365 } else {
366 // Notify the keyboard that it is hidden now.
367 keyboard_->SetVisible(false);
368 }
369 SchedulePaint();
370 }
371
372 #if defined(OS_CHROMEOS)
373 void TouchBrowserFrameView::VirtualKeyboardChanged(
374 chromeos::input_method::InputMethodManager* manager,
375 const chromeos::input_method::VirtualKeyboard& virtual_keyboard,
376 const std::string& virtual_keyboard_layout) {
377 const GURL& new_url =
378 virtual_keyboard.GetURLForLayout(virtual_keyboard_layout);
379 if (new_url == url_)
380 return;
381
382 url_ = new_url;
383 if (keyboard_)
384 keyboard_->LoadURL(url_);
385 // |keyboard_| can be NULL here. In that case, the |url_| will be used in
386 // InitVirtualKeyboard() later.
387 }
388 #endif
OLDNEW
« no previous file with comments | « chrome/browser/ui/touch/frame/touch_browser_frame_view.h ('k') | chrome/browser/ui/touch/keyboard/keyboard_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698