OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/chromeos/login/touch_login_view.h" | |
6 | |
7 #include "chrome/browser/chromeos/status/status_area_view.h" | |
8 #include "chrome/browser/profiles/profile.h" | |
9 #include "chrome/browser/renderer_host/render_widget_host_view_views.h" | |
10 #include "chrome/browser/ui/touch/frame/keyboard_container_view.h" | |
11 #include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h" | |
12 #include "chrome/browser/ui/views/dom_view.h" | |
13 #include "chrome/common/chrome_notification_types.h" | |
14 #include "content/browser/tab_contents/tab_contents.h" | |
15 #include "content/common/notification_service.h" | |
16 #include "googleurl/src/gurl.h" | |
17 #include "ui/base/animation/slide_animation.h" | |
18 #include "ui/gfx/transform.h" | |
19 #include "views/controls/textfield/textfield.h" | |
20 #include "views/widget/widget.h" | |
21 | |
22 namespace { | |
23 | |
24 const char kViewClassName[] = "browser/chromeos/login/TouchLoginView"; | |
25 const int kDefaultKeyboardHeight = 300; | |
26 const int kKeyboardSlideDuration = 300; // In milliseconds | |
27 | |
28 PropertyAccessor<bool>* GetFocusedStateAccessor() { | |
29 static PropertyAccessor<bool> state; | |
30 return &state; | |
31 } | |
32 | |
33 bool TabContentsHasFocus(const TabContents* contents) { | |
34 views::View* view = static_cast<TabContentsViewTouch*>(contents->view()); | |
35 return view->Contains(view->GetFocusManager()->GetFocusedView()); | |
36 } | |
37 | |
38 } // namespace | |
39 | |
40 namespace chromeos { | |
41 | |
42 // TouchLoginView public: ------------------------------------------------------ | |
43 | |
44 TouchLoginView::TouchLoginView() | |
45 : WebUILoginView(), | |
46 keyboard_showing_(false), | |
47 keyboard_height_(kDefaultKeyboardHeight), | |
48 focus_listener_added_(false), | |
49 keyboard_(NULL) { | |
50 } | |
51 | |
52 TouchLoginView::~TouchLoginView() { | |
53 } | |
54 | |
55 void TouchLoginView::Init() { | |
56 WebUILoginView::Init(); | |
57 InitStatusArea(); | |
58 InitVirtualKeyboard(); | |
59 | |
60 | |
61 Source<TabContents> tab_contents(webui_login_->tab_contents()); | |
62 registrar_.Add(this, | |
63 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE, | |
64 tab_contents); | |
65 registrar_.Add(this, | |
66 content::NOTIFICATION_TAB_CONTENTS_DESTROYED, | |
67 tab_contents); | |
68 registrar_.Add(this, | |
69 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED, | |
70 NotificationService::AllSources()); | |
71 registrar_.Add(this, | |
72 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED, | |
73 NotificationService::AllSources()); | |
74 } | |
75 | |
76 std::string TouchLoginView::GetClassName() const { | |
77 return kViewClassName; | |
78 } | |
79 | |
80 void TouchLoginView::FocusWillChange(views::View* focused_before, | |
81 views::View* focused_now) { | |
82 VirtualKeyboardType before = DecideKeyboardStateForView(focused_before); | |
83 VirtualKeyboardType now = DecideKeyboardStateForView(focused_now); | |
84 if (before != now) { | |
85 // TODO(varunjain): support other types of keyboard. | |
86 UpdateKeyboardAndLayout(now == GENERIC); | |
87 } | |
88 } | |
89 | |
90 void TouchLoginView::OnWindowCreated() { | |
91 } | |
92 | |
93 // TouchLoginView protected: --------------------------------------------------- | |
94 | |
95 void TouchLoginView::Layout() { | |
96 WebUILoginView::Layout(); | |
97 DCHECK(status_area_); | |
98 | |
99 // Layout the Status Area up in the right corner. This should always be done. | |
100 gfx::Size status_area_size = status_area_->GetPreferredSize(); | |
101 status_area_->SetBounds( | |
102 width() - status_area_size.width() - | |
103 WebUILoginView::kStatusAreaCornerPadding, | |
104 WebUILoginView::kStatusAreaCornerPadding, | |
105 status_area_size.width(), | |
106 status_area_size.height()); | |
107 | |
108 if (!keyboard_) | |
109 return; | |
110 | |
111 // We are not resizing the DOMView here, so the keyboard is going to occlude | |
112 // the login screen partially. It is the responsibility of the UX layer to | |
113 // handle this. | |
114 | |
115 // Lastly layout the keyboard | |
116 bool display_keyboard = (keyboard_showing_ || animation_->is_animating()); | |
117 keyboard_->SetVisible(display_keyboard); | |
118 gfx::Rect keyboard_bounds = bounds(); | |
119 int keyboard_height = display_keyboard ? keyboard_height_ : 0; | |
120 keyboard_bounds.set_y(keyboard_bounds.height() - keyboard_height); | |
121 keyboard_bounds.set_height(keyboard_height); | |
122 keyboard_->SetBoundsRect(keyboard_bounds); | |
123 } | |
124 | |
125 void TouchLoginView::InitStatusArea() { | |
126 if (status_area_) | |
127 return; | |
128 status_area_ = new StatusAreaView(this); | |
129 status_area_->Init(); | |
130 AddChildView(status_area_); | |
131 } | |
132 | |
133 // TouchLoginView private: ----------------------------------------------------- | |
134 | |
135 void TouchLoginView::InitVirtualKeyboard() { | |
136 // TODO(yusukes): Support non-US virtual keyboard on the login screen. | |
137 keyboard_ = new KeyboardContainerView(profile_, NULL, GURL()); | |
138 | |
139 keyboard_->SetVisible(false); | |
140 AddChildView(keyboard_); | |
141 | |
142 animation_.reset(new ui::SlideAnimation(this)); | |
143 animation_->SetTweenType(ui::Tween::LINEAR); | |
144 animation_->SetSlideDuration(kKeyboardSlideDuration); | |
145 } | |
146 | |
147 void TouchLoginView::UpdateKeyboardAndLayout(bool should_show_keyboard) { | |
148 DCHECK(keyboard_); | |
149 if (should_show_keyboard == keyboard_showing_) | |
150 return; | |
151 keyboard_showing_ = should_show_keyboard; | |
152 if (keyboard_showing_) { | |
153 ui::Transform transform; | |
154 transform.SetTranslateY(-keyboard_height_); | |
155 keyboard_->SetTransform(transform); | |
156 Layout(); | |
157 animation_->Show(); | |
158 } else { | |
159 ui::Transform transform; | |
160 keyboard_->SetTransform(transform); | |
161 animation_->Hide(); | |
162 Layout(); | |
163 } | |
164 } | |
165 | |
166 TouchLoginView::VirtualKeyboardType | |
167 TouchLoginView::DecideKeyboardStateForView(views::View* view) { | |
168 if (!view) | |
169 return NONE; | |
170 | |
171 std::string cname = view->GetClassName(); | |
172 if (cname == views::Textfield::kViewClassName) { | |
173 return GENERIC; | |
174 } else if (cname == RenderWidgetHostViewViews::kViewClassName) { | |
175 TabContents* contents = webui_login_->tab_contents(); | |
176 bool* editable = contents ? GetFocusedStateAccessor()->GetProperty( | |
177 contents->property_bag()) : NULL; | |
178 if (editable && *editable) | |
179 return GENERIC; | |
180 } | |
181 return NONE; | |
182 } | |
183 | |
184 void TouchLoginView::Observe(int type, | |
185 const NotificationSource& source, | |
186 const NotificationDetails& details) { | |
187 if (type == content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE) { | |
188 // Only modify the keyboard state if the currently active tab sent the | |
189 // notification. | |
190 const TabContents* current_tab = webui_login_->tab_contents(); | |
191 TabContents* source_tab = Source<TabContents>(source).ptr(); | |
192 const bool editable = *Details<const bool>(details).ptr(); | |
193 | |
194 if (current_tab == source_tab && TabContentsHasFocus(source_tab)) | |
195 UpdateKeyboardAndLayout(editable); | |
196 | |
197 // Save the state of the focused field so that the keyboard visibility | |
198 // can be determined after tab switching. | |
199 GetFocusedStateAccessor()->SetProperty( | |
200 source_tab->property_bag(), editable); | |
201 } else if (type == content::NOTIFICATION_TAB_CONTENTS_DESTROYED) { | |
202 GetFocusedStateAccessor()->DeleteProperty( | |
203 Source<TabContents>(source).ptr()->property_bag()); | |
204 } else if (type == chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED) { | |
205 UpdateKeyboardAndLayout(false); | |
206 } else if (type == chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED) { | |
207 // TODO(penghuang) Allow extension conrtol the virtual keyboard directly | |
208 // instead of using Notification. | |
209 int height = *(Details<int>(details).ptr()); | |
210 if (height != keyboard_height_) { | |
211 DCHECK_GE(height, 0) << "Height of the keyboard is less than 0."; | |
212 DCHECK_LE(height, View::height()) << "Height of the keyboard is greater " | |
213 "than the height of containing view."; | |
214 keyboard_height_ = height; | |
215 Layout(); | |
216 } | |
217 } | |
218 } | |
219 | |
220 // ui::AnimationDelegate implementation ---------------------------------------- | |
221 | |
222 void TouchLoginView::AnimationProgressed(const ui::Animation* anim) { | |
223 ui::Transform transform; | |
224 transform.SetTranslateY( | |
225 ui::Tween::ValueBetween(anim->GetCurrentValue(), keyboard_height_, 0)); | |
226 keyboard_->SetTransform(transform); | |
227 } | |
228 | |
229 void TouchLoginView::AnimationEnded(const ui::Animation* animation) { | |
230 if (keyboard_showing_) { | |
231 Layout(); | |
232 } else { | |
233 // Notify the keyboard that it is hidden now. | |
234 keyboard_->SetVisible(false); | |
235 } | |
236 } | |
237 | |
238 } // namespace chromeos | |
OLD | NEW |