| 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/user_controller.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/utf_string_conversions.h" | |
| 11 #include "chrome/browser/chromeos/login/existing_user_view.h" | |
| 12 #include "chrome/browser/chromeos/login/guest_user_view.h" | |
| 13 #include "chrome/browser/chromeos/login/helper.h" | |
| 14 #include "chrome/browser/chromeos/login/rounded_rect_painter.h" | |
| 15 #include "chrome/browser/chromeos/login/user_view.h" | |
| 16 #include "chrome/browser/chromeos/login/username_view.h" | |
| 17 #include "chrome/browser/chromeos/login/wizard_accessibility_helper.h" | |
| 18 #include "chrome/browser/chromeos/login/wizard_controller.h" | |
| 19 #include "chrome/browser/chromeos/user_cros_settings_provider.h" | |
| 20 #include "grit/generated_resources.h" | |
| 21 #include "grit/theme_resources.h" | |
| 22 #include "third_party/cros_system_api/window_manager/chromeos_wm_ipc_enums.h" | |
| 23 #include "ui/base/l10n/l10n_util.h" | |
| 24 #include "ui/base/resource/resource_bundle.h" | |
| 25 #include "ui/gfx/canvas.h" | |
| 26 #include "views/background.h" | |
| 27 #include "views/controls/label.h" | |
| 28 #include "views/controls/throbber.h" | |
| 29 #include "views/focus/focus_manager.h" | |
| 30 #include "views/painter.h" | |
| 31 #include "views/widget/widget.h" | |
| 32 | |
| 33 using views::Widget; | |
| 34 | |
| 35 namespace chromeos { | |
| 36 | |
| 37 namespace { | |
| 38 | |
| 39 // Gap between the border around the image/buttons and user name. | |
| 40 const int kUserNameGap = 4; | |
| 41 | |
| 42 // Approximate height of controls window, this constant is used in new user | |
| 43 // case to make border window size close to existing users. | |
| 44 #if defined(CROS_FONTS_USING_BCI) | |
| 45 const int kControlsHeight = 31; | |
| 46 #else | |
| 47 const int kControlsHeight = 28; | |
| 48 #endif | |
| 49 | |
| 50 // Vertical interval between the image and the textfield. | |
| 51 const int kVerticalIntervalSize = 10; | |
| 52 | |
| 53 void CloseWindow(views::Widget* window) { | |
| 54 if (window) | |
| 55 window->CloseNow(); | |
| 56 } | |
| 57 | |
| 58 } // namespace | |
| 59 | |
| 60 // WidgetDelegate implementation for the Widget used for the controls. | |
| 61 class UserController::ControlsWidgetDelegate : public views::WidgetDelegate { | |
| 62 public: | |
| 63 ControlsWidgetDelegate(UserController* controller, | |
| 64 views::View* view) | |
| 65 : controller_(controller), | |
| 66 view_(view) { | |
| 67 } | |
| 68 | |
| 69 virtual views::View* GetInitiallyFocusedView() OVERRIDE { | |
| 70 return view_; | |
| 71 } | |
| 72 | |
| 73 virtual views::Widget* GetWidget() OVERRIDE { | |
| 74 return view_->GetWidget(); | |
| 75 } | |
| 76 virtual const views::Widget* GetWidget() const OVERRIDE { | |
| 77 return view_->GetWidget(); | |
| 78 } | |
| 79 | |
| 80 private: | |
| 81 UserController* controller_; | |
| 82 | |
| 83 // View to give focus to on show. | |
| 84 views::View* view_; | |
| 85 | |
| 86 DISALLOW_COPY_AND_ASSIGN(ControlsWidgetDelegate); | |
| 87 }; | |
| 88 | |
| 89 using login::kBorderSize; | |
| 90 using login::kUserImageSize; | |
| 91 | |
| 92 // static | |
| 93 const int UserController::kPadding = 30; | |
| 94 | |
| 95 // Max size needed when an entry is not selected. | |
| 96 const int UserController::kUnselectedSize = 100; | |
| 97 const int UserController::kNewUserUnselectedSize = 42; | |
| 98 | |
| 99 //////////////////////////////////////////////////////////////////////////////// | |
| 100 // UserController, public: | |
| 101 | |
| 102 UserController::UserController(Delegate* delegate, bool is_guest) | |
| 103 : user_index_(-1), | |
| 104 is_user_selected_(false), | |
| 105 is_new_user_(!is_guest), | |
| 106 is_guest_(is_guest), | |
| 107 is_owner_(false), | |
| 108 show_name_tooltip_(false), | |
| 109 delegate_(delegate), | |
| 110 controls_widget_(NULL), | |
| 111 image_widget_(NULL), | |
| 112 border_window_(NULL), | |
| 113 label_widget_(NULL), | |
| 114 unselected_label_widget_(NULL), | |
| 115 user_view_(NULL), | |
| 116 label_view_(NULL), | |
| 117 unselected_label_view_(NULL), | |
| 118 user_input_(NULL), | |
| 119 throbber_host_(NULL) { | |
| 120 } | |
| 121 | |
| 122 UserController::UserController(Delegate* delegate, | |
| 123 const UserManager::User& user) | |
| 124 : user_index_(-1), | |
| 125 is_user_selected_(false), | |
| 126 is_new_user_(false), | |
| 127 is_guest_(false), | |
| 128 // Empty 'cached_owner()' means that owner hasn't been cached yet, not | |
| 129 // that owner has an empty email. | |
| 130 is_owner_(user.email() == UserCrosSettingsProvider::cached_owner()), | |
| 131 show_name_tooltip_(false), | |
| 132 user_(user), | |
| 133 delegate_(delegate), | |
| 134 controls_widget_(NULL), | |
| 135 image_widget_(NULL), | |
| 136 border_window_(NULL), | |
| 137 label_widget_(NULL), | |
| 138 unselected_label_widget_(NULL), | |
| 139 user_view_(NULL), | |
| 140 label_view_(NULL), | |
| 141 unselected_label_view_(NULL), | |
| 142 user_input_(NULL), | |
| 143 throbber_host_(NULL) { | |
| 144 DCHECK(!user.email().empty()); | |
| 145 } | |
| 146 | |
| 147 UserController::~UserController() { | |
| 148 // Reset the widget delegate of every window to NULL, so the user | |
| 149 // controller will not get notified about the active window change. | |
| 150 // See also crosbug.com/7400. | |
| 151 CloseWindow(controls_widget_); | |
| 152 CloseWindow(image_widget_); | |
| 153 CloseWindow(border_window_); | |
| 154 CloseWindow(label_widget_); | |
| 155 CloseWindow(unselected_label_widget_); | |
| 156 } | |
| 157 | |
| 158 void UserController::Init(int index, | |
| 159 int total_user_count, | |
| 160 bool need_browse_without_signin) { | |
| 161 int controls_height = 0; | |
| 162 int controls_width = 0; | |
| 163 SetupControlsWidget(index, &controls_width, &controls_height, | |
| 164 need_browse_without_signin); | |
| 165 image_widget_ = CreateImageWidget(index); | |
| 166 CreateBorderWindow(index, total_user_count, controls_width, controls_height); | |
| 167 label_widget_ = CreateLabelWidget(index, WM_IPC_WINDOW_LOGIN_LABEL); | |
| 168 unselected_label_widget_ = | |
| 169 CreateLabelWidget(index, WM_IPC_WINDOW_LOGIN_UNSELECTED_LABEL); | |
| 170 } | |
| 171 | |
| 172 void UserController::ClearAndEnableFields() { | |
| 173 user_input_->EnableInputControls(true); | |
| 174 user_input_->ClearAndFocusControls(); | |
| 175 StopThrobber(); | |
| 176 } | |
| 177 | |
| 178 void UserController::ClearAndEnablePassword() { | |
| 179 // Somehow focus manager thinks that textfield is still focused but the | |
| 180 // textfield doesn't know that. So we clear focus for focus manager so it | |
| 181 // sets focus on the textfield again. | |
| 182 // TODO(avayvod): Fix the actual issue. | |
| 183 views::FocusManager* focus_manager = controls_widget_->GetFocusManager(); | |
| 184 if (focus_manager) | |
| 185 focus_manager->ClearFocus(); | |
| 186 user_input_->EnableInputControls(true); | |
| 187 user_input_->ClearAndFocusPassword(); | |
| 188 StopThrobber(); | |
| 189 } | |
| 190 | |
| 191 void UserController::EnableNameTooltip(bool enable) { | |
| 192 name_tooltip_enabled_ = enable; | |
| 193 string16 tooltip_text; | |
| 194 if (enable) | |
| 195 tooltip_text = GetNameTooltip(); | |
| 196 | |
| 197 if (user_view_) | |
| 198 user_view_->SetTooltipText(tooltip_text); | |
| 199 if (label_view_) | |
| 200 label_view_->SetTooltipText(tooltip_text); | |
| 201 if (unselected_label_view_) | |
| 202 unselected_label_view_->SetTooltipText(tooltip_text); | |
| 203 } | |
| 204 | |
| 205 gfx::Rect UserController::GetMainInputScreenBounds() const { | |
| 206 return user_input_->GetMainInputScreenBounds(); | |
| 207 } | |
| 208 | |
| 209 void UserController::OnUserImageChanged(UserManager::User* user) { | |
| 210 if (user_.email() != user->email()) | |
| 211 return; | |
| 212 user_.SetImage(user->image(), user->default_image_index()); | |
| 213 // Controller might exist without windows, | |
| 214 // i.e. if user pod doesn't fit on the screen. | |
| 215 if (user_view_) | |
| 216 user_view_->SetImage(user_.image(), user_.image()); | |
| 217 } | |
| 218 | |
| 219 void UserController::SelectUserRelative(int shift) { | |
| 220 delegate_->SelectUser(user_index() + shift); | |
| 221 } | |
| 222 | |
| 223 void UserController::StartThrobber() { | |
| 224 throbber_host_->StartThrobber(); | |
| 225 } | |
| 226 | |
| 227 void UserController::StopThrobber() { | |
| 228 throbber_host_->StopThrobber(); | |
| 229 } | |
| 230 | |
| 231 void UserController::UpdateUserCount(int index, int total_user_count) { | |
| 232 #if defined(TOOLKIT_USES_GTK) | |
| 233 user_index_ = index; | |
| 234 std::vector<int> params; | |
| 235 params.push_back(index); | |
| 236 params.push_back(total_user_count); | |
| 237 params.push_back(is_new_user_ ? kNewUserUnselectedSize : kUnselectedSize); | |
| 238 params.push_back(kPadding); | |
| 239 WmIpc::instance()->SetWindowType( | |
| 240 border_window_->GetNativeView(), | |
| 241 WM_IPC_WINDOW_LOGIN_BORDER, | |
| 242 ¶ms); | |
| 243 #endif | |
| 244 } | |
| 245 | |
| 246 std::string UserController::GetAccessibleUserLabel() { | |
| 247 if (is_new_user_) | |
| 248 return l10n_util::GetStringUTF8(IDS_ADD_USER); | |
| 249 if (is_guest_) | |
| 250 return l10n_util::GetStringUTF8(IDS_GUEST); | |
| 251 return user_.email(); | |
| 252 } | |
| 253 | |
| 254 //////////////////////////////////////////////////////////////////////////////// | |
| 255 // UserController, WidgetDelegate implementation: | |
| 256 // | |
| 257 views::Widget* UserController::GetWidget() { | |
| 258 return NULL; | |
| 259 } | |
| 260 | |
| 261 const views::Widget* UserController::GetWidget() const { | |
| 262 return NULL; | |
| 263 } | |
| 264 | |
| 265 //////////////////////////////////////////////////////////////////////////////// | |
| 266 // UserController, NewUserView::Delegate implementation: | |
| 267 // | |
| 268 void UserController::OnLogin(const std::string& username, | |
| 269 const std::string& password) { | |
| 270 if (is_new_user_) | |
| 271 user_.set_email(username); | |
| 272 | |
| 273 user_input_->EnableInputControls(false); | |
| 274 StartThrobber(); | |
| 275 | |
| 276 delegate_->Login(this, UTF8ToUTF16(password)); | |
| 277 } | |
| 278 | |
| 279 void UserController::OnCreateAccount() { | |
| 280 user_input_->EnableInputControls(false); | |
| 281 StartThrobber(); | |
| 282 | |
| 283 delegate_->CreateAccount(); | |
| 284 } | |
| 285 | |
| 286 void UserController::OnStartEnterpriseEnrollment() { | |
| 287 delegate_->StartEnterpriseEnrollment(); | |
| 288 } | |
| 289 | |
| 290 void UserController::OnLoginAsGuest() { | |
| 291 user_input_->EnableInputControls(false); | |
| 292 StartThrobber(); | |
| 293 | |
| 294 delegate_->LoginAsGuest(); | |
| 295 } | |
| 296 | |
| 297 void UserController::ClearErrors() { | |
| 298 delegate_->ClearErrors(); | |
| 299 } | |
| 300 | |
| 301 void UserController::NavigateAway() { | |
| 302 SelectUserRelative(-1); | |
| 303 } | |
| 304 | |
| 305 //////////////////////////////////////////////////////////////////////////////// | |
| 306 // UserController, UserView::Delegate implementation: | |
| 307 // | |
| 308 void UserController::OnLocaleChanged() { | |
| 309 // Update text tooltips on guest and new user pods. | |
| 310 if (is_guest_ || is_new_user_) { | |
| 311 if (name_tooltip_enabled_) | |
| 312 EnableNameTooltip(name_tooltip_enabled_); | |
| 313 } | |
| 314 label_view_->SetFont(GetLabelFont()); | |
| 315 unselected_label_view_->SetFont(GetUnselectedLabelFont()); | |
| 316 } | |
| 317 | |
| 318 void UserController::OnRemoveUser() { | |
| 319 delegate_->RemoveUser(this); | |
| 320 } | |
| 321 | |
| 322 bool UserController::IsUserSelected() const { | |
| 323 return is_user_selected_; | |
| 324 } | |
| 325 | |
| 326 //////////////////////////////////////////////////////////////////////////////// | |
| 327 // UserController, views::Widget::Observer implementation: | |
| 328 // | |
| 329 void UserController::OnWidgetActivationChanged(views::Widget* widget, | |
| 330 bool active) { | |
| 331 is_user_selected_ = active; | |
| 332 if (active) { | |
| 333 delegate_->OnUserSelected(this); | |
| 334 user_view_->SetRemoveButtonVisible( | |
| 335 !is_new_user_ && !is_guest_ && !is_owner_); | |
| 336 } else { | |
| 337 user_view_->SetRemoveButtonVisible(false); | |
| 338 delegate_->ClearErrors(); | |
| 339 } | |
| 340 } | |
| 341 | |
| 342 //////////////////////////////////////////////////////////////////////////////// | |
| 343 // UserController, private: | |
| 344 // | |
| 345 void UserController::ConfigureAndShow(Widget* widget, | |
| 346 int index, | |
| 347 chromeos::WmIpcWindowType type, | |
| 348 views::View* contents_view) { | |
| 349 widget->SetContentsView(contents_view); | |
| 350 | |
| 351 #if defined(TOOLKIT_USES_GTK) | |
| 352 std::vector<int> params; | |
| 353 params.push_back(index); | |
| 354 WmIpc::instance()->SetWindowType( | |
| 355 widget->GetNativeView(), | |
| 356 type, | |
| 357 ¶ms); | |
| 358 #endif | |
| 359 | |
| 360 widget->Show(); | |
| 361 } | |
| 362 | |
| 363 void UserController::SetupControlsWidget( | |
| 364 int index, | |
| 365 int* width, int* height, | |
| 366 bool need_browse_without_signin) { | |
| 367 views::View* control_view; | |
| 368 if (is_new_user_) { | |
| 369 NewUserView* new_user_view = | |
| 370 new NewUserView(this, need_browse_without_signin); | |
| 371 new_user_view->Init(); | |
| 372 control_view = new_user_view; | |
| 373 user_input_ = new_user_view; | |
| 374 throbber_host_ = new_user_view; | |
| 375 } else if (is_guest_) { | |
| 376 GuestUserView* guest_user_view = new GuestUserView(this); | |
| 377 guest_user_view->RecreateFields(); | |
| 378 control_view = guest_user_view; | |
| 379 user_input_ = guest_user_view; | |
| 380 throbber_host_ = guest_user_view; | |
| 381 } else { | |
| 382 ExistingUserView* existing_user_view = new ExistingUserView(this); | |
| 383 existing_user_view->RecreateFields(); | |
| 384 control_view = existing_user_view; | |
| 385 user_input_ = existing_user_view; | |
| 386 throbber_host_ = existing_user_view; | |
| 387 } | |
| 388 | |
| 389 *height = kControlsHeight; | |
| 390 *width = kUserImageSize; | |
| 391 if (is_new_user_) { | |
| 392 gfx::Size size = control_view->GetPreferredSize(); | |
| 393 *width = size.width(); | |
| 394 *height = size.height(); | |
| 395 } | |
| 396 | |
| 397 controls_widget_delegate_.reset( | |
| 398 new ControlsWidgetDelegate(this, control_view)); | |
| 399 controls_widget_ = CreateControlsWidget(controls_widget_delegate_.get(), | |
| 400 gfx::Rect(*width, *height)); | |
| 401 controls_widget_->AddObserver(this); | |
| 402 ConfigureAndShow(controls_widget_, index, WM_IPC_WINDOW_LOGIN_CONTROLS, | |
| 403 control_view); | |
| 404 } | |
| 405 | |
| 406 Widget* UserController::CreateImageWidget(int index) { | |
| 407 user_view_ = new UserView(this, true, !is_new_user_); | |
| 408 | |
| 409 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 410 if (is_guest_) { | |
| 411 SkBitmap* image = rb.GetBitmapNamed(IDR_LOGIN_GUEST); | |
| 412 user_view_->SetImage(*image, *image); | |
| 413 } else if (is_new_user_) { | |
| 414 SkBitmap* image = rb.GetBitmapNamed(IDR_LOGIN_ADD_USER); | |
| 415 SkBitmap* image_hover = rb.GetBitmapNamed(IDR_LOGIN_ADD_USER_HOVER); | |
| 416 user_view_->SetImage(*image, *image_hover); | |
| 417 } else { | |
| 418 user_view_->SetImage(user_.image(), user_.image()); | |
| 419 } | |
| 420 | |
| 421 Widget* widget = | |
| 422 CreateClickNotifyingWidget(this, | |
| 423 gfx::Rect(user_view_->GetPreferredSize())); | |
| 424 widget->AddObserver(this); | |
| 425 ConfigureAndShow(widget, index, WM_IPC_WINDOW_LOGIN_IMAGE, user_view_); | |
| 426 | |
| 427 return widget; | |
| 428 } | |
| 429 | |
| 430 void UserController::CreateBorderWindow(int index, | |
| 431 int total_user_count, | |
| 432 int controls_width, | |
| 433 int controls_height) { | |
| 434 // New user login controls window is much higher than existing user's controls | |
| 435 // window so window manager will place the control instead of image window. | |
| 436 // New user will have 0 size border. | |
| 437 int width = controls_width; | |
| 438 int height = controls_height; | |
| 439 if (!is_new_user_) { | |
| 440 width += kBorderSize * 2; | |
| 441 height += 2 * kBorderSize + kUserImageSize + kVerticalIntervalSize; | |
| 442 } | |
| 443 | |
| 444 border_window_ = new Widget; | |
| 445 Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS); | |
| 446 params.transparent = true; | |
| 447 params.bounds = gfx::Rect(0, 0, width, height); | |
| 448 border_window_->Init(params); | |
| 449 if (!is_new_user_) { | |
| 450 views::View* background_view = new views::View(); | |
| 451 views::Painter* painter = CreateWizardPainter( | |
| 452 &BorderDefinition::kUserBorder); | |
| 453 background_view->set_background( | |
| 454 views::Background::CreateBackgroundPainter(true, painter)); | |
| 455 border_window_->SetContentsView(background_view); | |
| 456 } | |
| 457 UpdateUserCount(index, total_user_count); | |
| 458 | |
| 459 GdkWindow* gdk_window = border_window_->GetNativeView()->window; | |
| 460 gdk_window_set_back_pixmap(gdk_window, NULL, false); | |
| 461 | |
| 462 border_window_->Show(); | |
| 463 } | |
| 464 | |
| 465 Widget* UserController::CreateLabelWidget(int index, WmIpcWindowType type) { | |
| 466 string16 text; | |
| 467 if (is_guest_) { | |
| 468 text = string16(); | |
| 469 } else if (is_new_user_) { | |
| 470 // Add user should have label only in activated state. | |
| 471 // When new user is the only, label is not needed. | |
| 472 if (type == WM_IPC_WINDOW_LOGIN_LABEL && index != 0) | |
| 473 text = l10n_util::GetStringUTF16(IDS_ADD_USER); | |
| 474 } else { | |
| 475 text = UTF8ToUTF16(user_.GetDisplayName()); | |
| 476 } | |
| 477 | |
| 478 views::Label* label = NULL; | |
| 479 | |
| 480 if (is_new_user_) { | |
| 481 label = new views::Label(text); | |
| 482 } else if (type == WM_IPC_WINDOW_LOGIN_LABEL) { | |
| 483 label = UsernameView::CreateShapedUsernameView(UTF16ToWide(text), false); | |
| 484 } else { | |
| 485 DCHECK(type == WM_IPC_WINDOW_LOGIN_UNSELECTED_LABEL); | |
| 486 // TODO(altimofeev): switch to the rounded username view. | |
| 487 label = UsernameView::CreateShapedUsernameView( | |
| 488 UTF16ToWideHack(text), true); | |
| 489 } | |
| 490 | |
| 491 const gfx::Font& font = (type == WM_IPC_WINDOW_LOGIN_LABEL) ? | |
| 492 GetLabelFont() : GetUnselectedLabelFont(); | |
| 493 label->SetFont(font); | |
| 494 label->SetAutoColorReadabilityEnabled(false); | |
| 495 label->SetEnabledColor(login::kTextColor); | |
| 496 | |
| 497 if (type == WM_IPC_WINDOW_LOGIN_LABEL) | |
| 498 label_view_ = label; | |
| 499 else | |
| 500 unselected_label_view_ = label; | |
| 501 | |
| 502 int width = (type == WM_IPC_WINDOW_LOGIN_LABEL) ? | |
| 503 kUserImageSize : kUnselectedSize; | |
| 504 if (is_new_user_) { | |
| 505 // Make label as small as possible to don't show tooltip. | |
| 506 width = 0; | |
| 507 } | |
| 508 int height = (type == WM_IPC_WINDOW_LOGIN_LABEL) ? | |
| 509 login::kSelectedLabelHeight : login::kUnselectedLabelHeight; | |
| 510 Widget* widget = CreateClickNotifyingWidget(this, | |
| 511 gfx::Rect(0, 0, width, height)); | |
| 512 ConfigureAndShow(widget, index, type, label); | |
| 513 return widget; | |
| 514 } | |
| 515 | |
| 516 gfx::Font UserController::GetLabelFont() { | |
| 517 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 518 return rb.GetFont(ResourceBundle::MediumBoldFont).DeriveFont( | |
| 519 kSelectedUsernameFontDelta); | |
| 520 } | |
| 521 | |
| 522 gfx::Font UserController::GetUnselectedLabelFont() { | |
| 523 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 524 return rb.GetFont(ResourceBundle::BaseFont).DeriveFont( | |
| 525 kUnselectedUsernameFontDelta, gfx::Font::BOLD); | |
| 526 } | |
| 527 | |
| 528 string16 UserController::GetNameTooltip() const { | |
| 529 if (is_new_user_) | |
| 530 return l10n_util::GetStringUTF16(IDS_ADD_USER); | |
| 531 else if (is_guest_) | |
| 532 return l10n_util::GetStringUTF16(IDS_GO_INCOGNITO_BUTTON); | |
| 533 else | |
| 534 return UTF8ToUTF16(user_.GetNameTooltip()); | |
| 535 } | |
| 536 | |
| 537 } // namespace chromeos | |
| OLD | NEW |