| 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 |