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

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

Powered by Google App Engine
This is Rietveld 408576698