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

Side by Side Diff: ash/system/user/tray_user.cc

Issue 210903003: Implemented system tray UI for new account management. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge conflicts resolved. Created 6 years, 8 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
« no previous file with comments | « ash/system/user/tray_user.h ('k') | ash/system/user/user_accounts_delegate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "ash/system/user/tray_user.h" 5 #include "ash/system/user/tray_user.h"
6 6
7 #include <algorithm>
8 #include <climits>
9 #include <vector>
10
11 #include "ash/ash_switches.h" 7 #include "ash/ash_switches.h"
12 #include "ash/metrics/user_metrics_recorder.h"
13 #include "ash/multi_profile_uma.h"
14 #include "ash/popup_message.h"
15 #include "ash/root_window_controller.h" 8 #include "ash/root_window_controller.h"
16 #include "ash/session_state_delegate.h" 9 #include "ash/session_state_delegate.h"
17 #include "ash/shelf/shelf_layout_manager.h" 10 #include "ash/shelf/shelf_layout_manager.h"
18 #include "ash/shell.h"
19 #include "ash/shell_delegate.h" 11 #include "ash/shell_delegate.h"
20 #include "ash/system/tray/system_tray.h" 12 #include "ash/system/tray/system_tray.h"
21 #include "ash/system/tray/system_tray_delegate.h"
22 #include "ash/system/tray/system_tray_notifier.h" 13 #include "ash/system/tray/system_tray_notifier.h"
23 #include "ash/system/tray/tray_constants.h" 14 #include "ash/system/tray/tray_constants.h"
24 #include "ash/system/tray/tray_item_view.h" 15 #include "ash/system/tray/tray_item_view.h"
25 #include "ash/system/tray/tray_popup_label_button.h"
26 #include "ash/system/tray/tray_popup_label_button_border.h"
27 #include "ash/system/tray/tray_utils.h" 16 #include "ash/system/tray/tray_utils.h"
28 #include "base/i18n/rtl.h" 17 #include "ash/system/user/accounts_detailed_view.h"
18 #include "ash/system/user/rounded_image_view.h"
19 #include "ash/system/user/user_view.h"
29 #include "base/logging.h" 20 #include "base/logging.h"
30 #include "base/memory/scoped_vector.h"
31 #include "base/strings/string16.h" 21 #include "base/strings/string16.h"
32 #include "base/strings/string_util.h"
33 #include "base/strings/utf_string_conversions.h"
34 #include "grit/ash_resources.h"
35 #include "grit/ash_strings.h" 22 #include "grit/ash_strings.h"
36 #include "skia/ext/image_operations.h"
37 #include "third_party/skia/include/core/SkCanvas.h"
38 #include "third_party/skia/include/core/SkPaint.h"
39 #include "third_party/skia/include/core/SkPath.h"
40 #include "ui/aura/window.h" 23 #include "ui/aura/window.h"
41 #include "ui/base/l10n/l10n_util.h" 24 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/base/resource/resource_bundle.h"
43 #include "ui/gfx/canvas.h"
44 #include "ui/gfx/font_list.h"
45 #include "ui/gfx/image/image.h" 25 #include "ui/gfx/image/image.h"
46 #include "ui/gfx/image/image_skia_operations.h"
47 #include "ui/gfx/insets.h"
48 #include "ui/gfx/range/range.h"
49 #include "ui/gfx/rect.h"
50 #include "ui/gfx/render_text.h"
51 #include "ui/gfx/size.h"
52 #include "ui/gfx/skia_util.h"
53 #include "ui/gfx/text_elider.h"
54 #include "ui/gfx/text_utils.h"
55 #include "ui/views/border.h" 26 #include "ui/views/border.h"
56 #include "ui/views/bubble/tray_bubble_view.h"
57 #include "ui/views/controls/button/button.h"
58 #include "ui/views/controls/button/custom_button.h"
59 #include "ui/views/controls/image_view.h"
60 #include "ui/views/controls/label.h" 27 #include "ui/views/controls/label.h"
61 #include "ui/views/controls/link.h"
62 #include "ui/views/controls/link_listener.h"
63 #include "ui/views/layout/box_layout.h" 28 #include "ui/views/layout/box_layout.h"
64 #include "ui/views/layout/fill_layout.h"
65 #include "ui/views/mouse_watcher.h"
66 #include "ui/views/painter.h"
67 #include "ui/views/view.h" 29 #include "ui/views/view.h"
68 #include "ui/views/widget/widget.h" 30 #include "ui/views/widget/widget.h"
69 #include "ui/wm/core/shadow_types.h"
70 31
71 namespace { 32 namespace {
72 33
73 const int kUserDetailsVerticalPadding = 5;
74 const int kUserCardVerticalPadding = 10;
75 const int kProfileRoundedCornerRadius = 2;
76 const int kUserIconSize = 27;
77 const int kUserIconLargeSize = 32;
78 const int kUserIconLargeCornerRadius = 2;
79 const int kUserLabelToIconPadding = 5; 34 const int kUserLabelToIconPadding = 5;
80 35
81 // When a hover border is used, it is starting this many pixels before the icon 36 const int kTrayAvatarLargeSize = 32;
82 // position. 37 const int kTrayAvatarLargeCornerRadius = 2;
83 const int kTrayUserTileHoverBorderInset = 10;
84
85 // The border color of the user button.
86 const SkColor kBorderColor = 0xffdcdcdc;
87
88 // The invisible word joiner character, used as a marker to indicate the start
89 // and end of the user's display name in the public account user card's text.
90 const base::char16 kDisplayNameMark[] = { 0x2060, 0 };
91
92 const int kPublicAccountLogoutButtonBorderImagesNormal[] = {
93 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
94 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
95 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
96 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
97 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
98 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
99 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
100 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
101 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
102 };
103
104 const int kPublicAccountLogoutButtonBorderImagesHovered[] = {
105 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
106 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
107 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
108 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
109 IDR_AURA_TRAY_POPUP_LABEL_BUTTON_HOVER_BACKGROUND,
110 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
111 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
112 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
113 IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
114 };
115
116 // Offsetting the popup message relative to the tray menu.
117 const int kPopupMessageOffset = 25;
118
119 // Switch to a user with the given |user_index|.
120 void SwitchUser(ash::MultiProfileIndex user_index) {
121 // Do not switch users when the log screen is presented.
122 if (ash::Shell::GetInstance()->session_state_delegate()->
123 IsUserSessionBlocked())
124 return;
125
126 DCHECK(user_index > 0);
127 ash::SessionStateDelegate* delegate =
128 ash::Shell::GetInstance()->session_state_delegate();
129 ash::MultiProfileUMA::RecordSwitchActiveUser(
130 ash::MultiProfileUMA::SWITCH_ACTIVE_USER_BY_TRAY);
131 delegate->SwitchActiveUser(delegate->GetUserID(user_index));
132 }
133 38
134 } // namespace 39 } // namespace
135 40
136 namespace ash { 41 namespace ash {
137 namespace tray {
138
139 // A custom image view with rounded edges.
140 class RoundedImageView : public views::View {
141 public:
142 // Constructs a new rounded image view with rounded corners of radius
143 // |corner_radius|. If |active_user| is set, the icon will be drawn in
144 // full colors - otherwise it will fade into the background.
145 RoundedImageView(int corner_radius, bool active_user);
146 virtual ~RoundedImageView();
147
148 // Set the image that should be displayed. The image contents is copied to the
149 // receiver's image.
150 void SetImage(const gfx::ImageSkia& img, const gfx::Size& size);
151
152 // Set the radii of the corners independently.
153 void SetCornerRadii(int top_left,
154 int top_right,
155 int bottom_right,
156 int bottom_left);
157
158 private:
159 // Overridden from views::View.
160 virtual gfx::Size GetPreferredSize() OVERRIDE;
161 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
162
163 gfx::ImageSkia image_;
164 gfx::ImageSkia resized_;
165 gfx::Size image_size_;
166 int corner_radius_[4];
167
168 // True if the given user is the active user and the icon should get
169 // painted as active.
170 bool active_user_;
171
172 DISALLOW_COPY_AND_ASSIGN(RoundedImageView);
173 };
174
175 // The user details shown in public account mode. This is essentially a label
176 // but with custom painting code as the text is styled with multiple colors and
177 // contains a link.
178 class PublicAccountUserDetails : public views::View,
179 public views::LinkListener {
180 public:
181 PublicAccountUserDetails(SystemTrayItem* owner, int used_width);
182 virtual ~PublicAccountUserDetails();
183
184 private:
185 // Overridden from views::View.
186 virtual void Layout() OVERRIDE;
187 virtual gfx::Size GetPreferredSize() OVERRIDE;
188 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
189
190 // Overridden from views::LinkListener.
191 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
192
193 // Calculate a preferred size that ensures the label text and the following
194 // link do not wrap over more than three lines in total for aesthetic reasons
195 // if possible.
196 void CalculatePreferredSize(SystemTrayItem* owner, int used_width);
197
198 base::string16 text_;
199 views::Link* learn_more_;
200 gfx::Size preferred_size_;
201 ScopedVector<gfx::RenderText> lines_;
202
203 DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails);
204 };
205
206 // The button which holds the user card in case of multi profile.
207 class UserCard : public views::CustomButton {
208 public:
209 UserCard(views::ButtonListener* listener, bool active_user);
210 virtual ~UserCard();
211
212 // Called when the border should remain even in the non highlighted state.
213 void ForceBorderVisible(bool show);
214
215 // Overridden from views::View
216 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
217 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
218
219 // Check if the item is hovered.
220 bool is_hovered_for_test() {return button_hovered_; }
221
222 private:
223 // Change the hover/active state of the "button" when the status changes.
224 void ShowActive();
225
226 // True if this is the active user.
227 bool is_active_user_;
228
229 // True if button is hovered.
230 bool button_hovered_;
231
232 // True if the border should be visible.
233 bool show_border_;
234
235 DISALLOW_COPY_AND_ASSIGN(UserCard);
236 };
237
238 class UserViewMouseWatcherHost : public views::MouseWatcherHost {
239 public:
240 explicit UserViewMouseWatcherHost(const gfx::Rect& screen_area)
241 : screen_area_(screen_area) {}
242 virtual ~UserViewMouseWatcherHost() {}
243
244 // Implementation of MouseWatcherHost.
245 virtual bool Contains(const gfx::Point& screen_point,
246 views::MouseWatcherHost::MouseEventType type) OVERRIDE {
247 return screen_area_.Contains(screen_point);
248 }
249
250 private:
251 gfx::Rect screen_area_;
252
253 DISALLOW_COPY_AND_ASSIGN(UserViewMouseWatcherHost);
254 };
255
256 // The view of a user item.
257 class UserView : public views::View,
258 public views::ButtonListener,
259 public views::MouseWatcherListener {
260 public:
261 UserView(SystemTrayItem* owner,
262 ash::user::LoginStatus login,
263 MultiProfileIndex index);
264 virtual ~UserView();
265
266 // Overridden from MouseWatcherListener:
267 virtual void MouseMovedOutOfHost() OVERRIDE;
268
269 TrayUser::TestState GetStateForTest() const;
270 gfx::Rect GetBoundsInScreenOfUserButtonForTest();
271
272 private:
273 // Overridden from views::View.
274 virtual gfx::Size GetPreferredSize() OVERRIDE;
275 virtual int GetHeightForWidth(int width) OVERRIDE;
276 virtual void Layout() OVERRIDE;
277
278 // Overridden from views::ButtonListener.
279 virtual void ButtonPressed(views::Button* sender,
280 const ui::Event& event) OVERRIDE;
281
282 void AddLogoutButton(user::LoginStatus login);
283 void AddUserCard(SystemTrayItem* owner, user::LoginStatus login);
284
285 // Create a user icon representation for the user card.
286 views::View* CreateIconForUserCard(user::LoginStatus login);
287
288 // Create the additional user card content for the retail logged in mode.
289 void AddLoggedInRetailModeUserCardContent();
290
291 // Create the additional user card content for the public mode.
292 void AddLoggedInPublicModeUserCardContent(SystemTrayItem* owner);
293
294 // Create the menu option to add another user. If |disabled| is set the user
295 // cannot actively click on the item.
296 void ToggleAddUserMenuOption();
297
298 // Returns true when multi profile is supported.
299 bool SupportsMultiProfile();
300
301 MultiProfileIndex multiprofile_index_;
302 // The view of the user card.
303 views::View* user_card_view_;
304
305 // This is the owner system tray item of this view.
306 SystemTrayItem* owner_;
307
308 // True if |user_card_view_| is a |UserView| - otherwise it is only a
309 // |views::View|.
310 bool is_user_card_;
311 views::View* logout_button_;
312 scoped_ptr<PopupMessage> popup_message_;
313 scoped_ptr<views::Widget> add_menu_option_;
314
315 // True when the add user panel is visible but not activatable.
316 bool add_user_visible_but_disabled_;
317
318 // The mouse watcher which takes care of out of window hover events.
319 scoped_ptr<views::MouseWatcher> mouse_watcher_;
320
321 DISALLOW_COPY_AND_ASSIGN(UserView);
322 };
323
324 // The menu item view which gets shown when the user clicks in multi profile
325 // mode onto the user item.
326 class AddUserView : public views::CustomButton,
327 public views::ButtonListener {
328 public:
329 // The |owner| is the view for which this view gets created. The |listener|
330 // will get notified when this item gets clicked.
331 AddUserView(UserCard* owner, views::ButtonListener* listener);
332 virtual ~AddUserView();
333
334 // Get the anchor view for a message.
335 views::View* anchor() { return anchor_; }
336
337 // Overridden from views::ButtonListener.
338 virtual void ButtonPressed(views::Button* sender,
339 const ui::Event& event) OVERRIDE;
340
341 private:
342 // Overridden from views::View.
343 virtual gfx::Size GetPreferredSize() OVERRIDE;
344 virtual int GetHeightForWidth(int width) OVERRIDE;
345 virtual void Layout() OVERRIDE;
346
347 // Create the additional client content for this item.
348 void AddContent();
349
350 // This is the content we create and show.
351 views::View* add_user_;
352
353 // This listener will get informed when someone clicks on this button.
354 views::ButtonListener* listener_;
355
356 // This is the owner view of this item.
357 UserCard* owner_;
358
359 // The anchor view for targetted bubble messages.
360 views::View* anchor_;
361
362 DISALLOW_COPY_AND_ASSIGN(AddUserView);
363 };
364
365 RoundedImageView::RoundedImageView(int corner_radius, bool active_user)
366 : active_user_(active_user) {
367 for (int i = 0; i < 4; ++i)
368 corner_radius_[i] = corner_radius;
369 }
370
371 RoundedImageView::~RoundedImageView() {}
372
373 void RoundedImageView::SetImage(const gfx::ImageSkia& img,
374 const gfx::Size& size) {
375 image_ = img;
376 image_size_ = size;
377
378 // Try to get the best image quality for the avatar.
379 resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_,
380 skia::ImageOperations::RESIZE_BEST, size);
381 if (GetWidget() && visible()) {
382 PreferredSizeChanged();
383 SchedulePaint();
384 }
385 }
386
387 void RoundedImageView::SetCornerRadii(int top_left,
388 int top_right,
389 int bottom_right,
390 int bottom_left) {
391 corner_radius_[0] = top_left;
392 corner_radius_[1] = top_right;
393 corner_radius_[2] = bottom_right;
394 corner_radius_[3] = bottom_left;
395 }
396
397 gfx::Size RoundedImageView::GetPreferredSize() {
398 return gfx::Size(image_size_.width() + GetInsets().width(),
399 image_size_.height() + GetInsets().height());
400 }
401
402 void RoundedImageView::OnPaint(gfx::Canvas* canvas) {
403 View::OnPaint(canvas);
404 gfx::Rect image_bounds(size());
405 image_bounds.ClampToCenteredSize(GetPreferredSize());
406 image_bounds.Inset(GetInsets());
407 const SkScalar kRadius[8] = {
408 SkIntToScalar(corner_radius_[0]),
409 SkIntToScalar(corner_radius_[0]),
410 SkIntToScalar(corner_radius_[1]),
411 SkIntToScalar(corner_radius_[1]),
412 SkIntToScalar(corner_radius_[2]),
413 SkIntToScalar(corner_radius_[2]),
414 SkIntToScalar(corner_radius_[3]),
415 SkIntToScalar(corner_radius_[3])
416 };
417 SkPath path;
418 path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius);
419 SkPaint paint;
420 paint.setAntiAlias(true);
421 paint.setXfermodeMode(active_user_ ? SkXfermode::kSrcOver_Mode :
422 SkXfermode::kLuminosity_Mode);
423 canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(),
424 path, paint);
425 }
426
427 PublicAccountUserDetails::PublicAccountUserDetails(SystemTrayItem* owner,
428 int used_width)
429 : learn_more_(NULL) {
430 const int inner_padding =
431 kTrayPopupPaddingHorizontal - kTrayPopupPaddingBetweenItems;
432 const bool rtl = base::i18n::IsRTL();
433 SetBorder(views::Border::CreateEmptyBorder(kUserDetailsVerticalPadding,
434 rtl ? 0 : inner_padding,
435 kUserDetailsVerticalPadding,
436 rtl ? inner_padding : 0));
437
438 // Retrieve the user's display name and wrap it with markers.
439 // Note that since this is a public account it always has to be the primary
440 // user.
441 base::string16 display_name =
442 Shell::GetInstance()->session_state_delegate()->GetUserDisplayName(0);
443 base::RemoveChars(display_name, kDisplayNameMark, &display_name);
444 display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0];
445 // Retrieve the domain managing the device and wrap it with markers.
446 base::string16 domain = base::UTF8ToUTF16(
447 Shell::GetInstance()->system_tray_delegate()->GetEnterpriseDomain());
448 base::RemoveChars(domain, kDisplayNameMark, &domain);
449 base::i18n::WrapStringWithLTRFormatting(&domain);
450 // Retrieve the label text, inserting the display name and domain.
451 text_ = l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL,
452 display_name, domain);
453
454 learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE));
455 learn_more_->SetUnderline(false);
456 learn_more_->set_listener(this);
457 AddChildView(learn_more_);
458
459 CalculatePreferredSize(owner, used_width);
460 }
461
462 PublicAccountUserDetails::~PublicAccountUserDetails() {}
463
464 void PublicAccountUserDetails::Layout() {
465 lines_.clear();
466 const gfx::Rect contents_area = GetContentsBounds();
467 if (contents_area.IsEmpty())
468 return;
469
470 // Word-wrap the label text.
471 const gfx::FontList font_list;
472 std::vector<base::string16> lines;
473 gfx::ElideRectangleText(text_, font_list, contents_area.width(),
474 contents_area.height(), gfx::ELIDE_LONG_WORDS,
475 &lines);
476 // Loop through the lines, creating a renderer for each.
477 gfx::Point position = contents_area.origin();
478 gfx::Range display_name(gfx::Range::InvalidRange());
479 for (std::vector<base::string16>::const_iterator it = lines.begin();
480 it != lines.end(); ++it) {
481 gfx::RenderText* line = gfx::RenderText::CreateInstance();
482 line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI);
483 line->SetText(*it);
484 const gfx::Size size(contents_area.width(), line->GetStringSize().height());
485 line->SetDisplayRect(gfx::Rect(position, size));
486 position.set_y(position.y() + size.height());
487
488 // Set the default text color for the line.
489 line->SetColor(kPublicAccountUserCardTextColor);
490
491 // If a range of the line contains the user's display name, apply a custom
492 // text color to it.
493 if (display_name.is_empty())
494 display_name.set_start(it->find(kDisplayNameMark));
495 if (!display_name.is_empty()) {
496 display_name.set_end(
497 it->find(kDisplayNameMark, display_name.start() + 1));
498 gfx::Range line_range(0, it->size());
499 line->ApplyColor(kPublicAccountUserCardNameColor,
500 display_name.Intersect(line_range));
501 // Update the range for the next line.
502 if (display_name.end() >= line_range.end())
503 display_name.set_start(0);
504 else
505 display_name = gfx::Range::InvalidRange();
506 }
507
508 lines_.push_back(line);
509 }
510
511 // Position the link after the label text, separated by a space. If it does
512 // not fit onto the last line of the text, wrap the link onto its own line.
513 const gfx::Size last_line_size = lines_.back()->GetStringSize();
514 const int space_width =
515 gfx::GetStringWidth(base::ASCIIToUTF16(" "), font_list);
516 const gfx::Size link_size = learn_more_->GetPreferredSize();
517 if (contents_area.width() - last_line_size.width() >=
518 space_width + link_size.width()) {
519 position.set_x(position.x() + last_line_size.width() + space_width);
520 position.set_y(position.y() - last_line_size.height());
521 }
522 position.set_y(position.y() - learn_more_->GetInsets().top());
523 gfx::Rect learn_more_bounds(position, link_size);
524 learn_more_bounds.Intersect(contents_area);
525 if (base::i18n::IsRTL()) {
526 const gfx::Insets insets = GetInsets();
527 learn_more_bounds.Offset(insets.right() - insets.left(), 0);
528 }
529 learn_more_->SetBoundsRect(learn_more_bounds);
530 }
531
532 gfx::Size PublicAccountUserDetails::GetPreferredSize() {
533 return preferred_size_;
534 }
535
536 void PublicAccountUserDetails::OnPaint(gfx::Canvas* canvas) {
537 for (ScopedVector<gfx::RenderText>::const_iterator it = lines_.begin();
538 it != lines_.end(); ++it) {
539 (*it)->Draw(canvas);
540 }
541 views::View::OnPaint(canvas);
542 }
543
544 void PublicAccountUserDetails::LinkClicked(views::Link* source,
545 int event_flags) {
546 DCHECK_EQ(source, learn_more_);
547 Shell::GetInstance()->system_tray_delegate()->ShowPublicAccountInfo();
548 }
549
550 void PublicAccountUserDetails::CalculatePreferredSize(SystemTrayItem* owner,
551 int used_width) {
552 const gfx::FontList font_list;
553 const gfx::Size link_size = learn_more_->GetPreferredSize();
554 const int space_width =
555 gfx::GetStringWidth(base::ASCIIToUTF16(" "), font_list);
556 const gfx::Insets insets = GetInsets();
557 views::TrayBubbleView* bubble_view =
558 owner->system_tray()->GetSystemBubble()->bubble_view();
559 int min_width = std::max(
560 link_size.width(),
561 bubble_view->GetPreferredSize().width() - (used_width + insets.width()));
562 int max_width = std::min(
563 gfx::GetStringWidth(text_, font_list) + space_width + link_size.width(),
564 bubble_view->GetMaximumSize().width() - (used_width + insets.width()));
565 // Do a binary search for the minimum width that ensures no more than three
566 // lines are needed. The lower bound is the minimum of the current bubble
567 // width and the width of the link (as no wrapping is permitted inside the
568 // link). The upper bound is the maximum of the largest allowed bubble width
569 // and the sum of the label text and link widths when put on a single line.
570 std::vector<base::string16> lines;
571 while (min_width < max_width) {
572 lines.clear();
573 const int width = (min_width + max_width) / 2;
574 const bool too_narrow =
575 gfx::ElideRectangleText(text_, font_list, width, INT_MAX,
576 gfx::TRUNCATE_LONG_WORDS, &lines) != 0;
577 int line_count = lines.size();
578 if (!too_narrow && line_count == 3 &&
579 width - gfx::GetStringWidth(lines.back(), font_list) <=
580 space_width + link_size.width())
581 ++line_count;
582 if (too_narrow || line_count > 3)
583 min_width = width + 1;
584 else
585 max_width = width;
586 }
587
588 // Calculate the corresponding height and set the preferred size.
589 lines.clear();
590 gfx::ElideRectangleText(
591 text_, font_list, min_width, INT_MAX, gfx::TRUNCATE_LONG_WORDS, &lines);
592 int line_count = lines.size();
593 if (min_width - gfx::GetStringWidth(lines.back(), font_list) <=
594 space_width + link_size.width()) {
595 ++line_count;
596 }
597 const int line_height = font_list.GetHeight();
598 const int link_extra_height = std::max(
599 link_size.height() - learn_more_->GetInsets().top() - line_height, 0);
600 preferred_size_ = gfx::Size(
601 min_width + insets.width(),
602 line_count * line_height + link_extra_height + insets.height());
603
604 bubble_view->SetWidth(preferred_size_.width() + used_width);
605 }
606
607 UserCard::UserCard(views::ButtonListener* listener, bool active_user)
608 : CustomButton(listener),
609 is_active_user_(active_user),
610 button_hovered_(false),
611 show_border_(false) {
612 if (is_active_user_) {
613 set_background(
614 views::Background::CreateSolidBackground(kBackgroundColor));
615 ShowActive();
616 }
617 }
618
619 UserCard::~UserCard() {}
620
621 void UserCard::ForceBorderVisible(bool show) {
622 show_border_ = show;
623 ShowActive();
624 }
625
626 void UserCard::OnMouseEntered(const ui::MouseEvent& event) {
627 if (is_active_user_) {
628 button_hovered_ = true;
629 background()->SetNativeControlColor(kHoverBackgroundColor);
630 ShowActive();
631 }
632 }
633
634 void UserCard::OnMouseExited(const ui::MouseEvent& event) {
635 if (is_active_user_) {
636 button_hovered_ = false;
637 background()->SetNativeControlColor(kBackgroundColor);
638 ShowActive();
639 }
640 }
641
642 void UserCard::ShowActive() {
643 int width = button_hovered_ || show_border_ ? 1 : 0;
644 SetBorder(views::Border::CreateSolidSidedBorder(
645 width, width, width, 1, kBorderColor));
646 SchedulePaint();
647 }
648
649 UserView::UserView(SystemTrayItem* owner,
650 user::LoginStatus login,
651 MultiProfileIndex index)
652 : multiprofile_index_(index),
653 user_card_view_(NULL),
654 owner_(owner),
655 is_user_card_(false),
656 logout_button_(NULL),
657 add_user_visible_but_disabled_(false) {
658 CHECK_NE(user::LOGGED_IN_NONE, login);
659 if (!index) {
660 // Only the logged in user will have a background. All other users will have
661 // to allow the TrayPopupContainer highlighting the menu line.
662 set_background(views::Background::CreateSolidBackground(
663 login == user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor :
664 kBackgroundColor));
665 }
666 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
667 kTrayPopupPaddingBetweenItems));
668 // The logout button must be added before the user card so that the user card
669 // can correctly calculate the remaining available width.
670 // Note that only the current multiprofile user gets a button.
671 if (!multiprofile_index_)
672 AddLogoutButton(login);
673 AddUserCard(owner, login);
674 }
675
676 UserView::~UserView() {}
677
678 void UserView::MouseMovedOutOfHost() {
679 popup_message_.reset();
680 mouse_watcher_.reset();
681 add_menu_option_.reset();
682 }
683
684 TrayUser::TestState UserView::GetStateForTest() const {
685 if (add_menu_option_.get()) {
686 return add_user_visible_but_disabled_ ? TrayUser::ACTIVE_BUT_DISABLED :
687 TrayUser::ACTIVE;
688 }
689
690 if (!is_user_card_)
691 return TrayUser::SHOWN;
692
693 return static_cast<UserCard*>(user_card_view_)->is_hovered_for_test() ?
694 TrayUser::HOVERED : TrayUser::SHOWN;
695 }
696
697 gfx::Rect UserView::GetBoundsInScreenOfUserButtonForTest() {
698 DCHECK(user_card_view_);
699 return user_card_view_->GetBoundsInScreen();
700 }
701
702 gfx::Size UserView::GetPreferredSize() {
703 gfx::Size size = views::View::GetPreferredSize();
704 // Only the active user panel will be forced to a certain height.
705 if (!multiprofile_index_) {
706 size.set_height(std::max(size.height(),
707 kTrayPopupItemHeight + GetInsets().height()));
708 }
709 return size;
710 }
711
712 int UserView::GetHeightForWidth(int width) {
713 return GetPreferredSize().height();
714 }
715
716 void UserView::Layout() {
717 gfx::Rect contents_area(GetContentsBounds());
718 if (user_card_view_ && logout_button_) {
719 // Give the logout button the space it requests.
720 gfx::Rect logout_area = contents_area;
721 logout_area.ClampToCenteredSize(logout_button_->GetPreferredSize());
722 logout_area.set_x(contents_area.right() - logout_area.width());
723
724 // Give the remaining space to the user card.
725 gfx::Rect user_card_area = contents_area;
726 int remaining_width = contents_area.width() - logout_area.width();
727 if (SupportsMultiProfile()) {
728 // In multiprofile case |user_card_view_| and |logout_button_| have to
729 // have the same height.
730 int y = std::min(user_card_area.y(), logout_area.y());
731 int height = std::max(user_card_area.height(), logout_area.height());
732 logout_area.set_y(y);
733 logout_area.set_height(height);
734 user_card_area.set_y(y);
735 user_card_area.set_height(height);
736
737 // In multiprofile mode we have also to increase the size of the card by
738 // the size of the border to make it overlap with the logout button.
739 user_card_area.set_width(std::max(0, remaining_width + 1));
740
741 // To make the logout button symmetrical with the user card we also make
742 // the button longer by the same size the hover area in front of the icon
743 // got inset.
744 logout_area.set_width(logout_area.width() +
745 kTrayUserTileHoverBorderInset);
746 } else {
747 // In all other modes we have to make sure that there is enough spacing
748 // between the two.
749 remaining_width -= kTrayPopupPaddingBetweenItems;
750 }
751 user_card_area.set_width(remaining_width);
752 user_card_view_->SetBoundsRect(user_card_area);
753 logout_button_->SetBoundsRect(logout_area);
754 } else if (user_card_view_) {
755 user_card_view_->SetBoundsRect(contents_area);
756 } else if (logout_button_) {
757 logout_button_->SetBoundsRect(contents_area);
758 }
759 }
760
761 void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) {
762 if (sender == logout_button_) {
763 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
764 ash::UMA_STATUS_AREA_SIGN_OUT);
765 Shell::GetInstance()->system_tray_delegate()->SignOut();
766 } else if (sender == user_card_view_ && SupportsMultiProfile()) {
767 if (!multiprofile_index_) {
768 ToggleAddUserMenuOption();
769 } else {
770 SwitchUser(multiprofile_index_);
771 // Since the user list is about to change the system menu should get
772 // closed.
773 owner_->system_tray()->CloseSystemBubble();
774 }
775 } else if (add_menu_option_.get() &&
776 sender == add_menu_option_->GetContentsView()) {
777 // Let the user add another account to the session.
778 MultiProfileUMA::RecordSigninUser(MultiProfileUMA::SIGNIN_USER_BY_TRAY);
779 Shell::GetInstance()->system_tray_delegate()->ShowUserLogin();
780 owner_->system_tray()->CloseSystemBubble();
781 } else {
782 NOTREACHED();
783 }
784 }
785
786 void UserView::AddLogoutButton(user::LoginStatus login) {
787 const base::string16 title = user::GetLocalizedSignOutStringForStatus(login,
788 true);
789 TrayPopupLabelButton* logout_button = new TrayPopupLabelButton(this, title);
790 logout_button->SetAccessibleName(title);
791 logout_button_ = logout_button;
792 // In public account mode, the logout button border has a custom color.
793 if (login == user::LOGGED_IN_PUBLIC) {
794 scoped_ptr<TrayPopupLabelButtonBorder> border(
795 new TrayPopupLabelButtonBorder());
796 border->SetPainter(false, views::Button::STATE_NORMAL,
797 views::Painter::CreateImageGridPainter(
798 kPublicAccountLogoutButtonBorderImagesNormal));
799 border->SetPainter(false, views::Button::STATE_HOVERED,
800 views::Painter::CreateImageGridPainter(
801 kPublicAccountLogoutButtonBorderImagesHovered));
802 border->SetPainter(false, views::Button::STATE_PRESSED,
803 views::Painter::CreateImageGridPainter(
804 kPublicAccountLogoutButtonBorderImagesHovered));
805 logout_button_->SetBorder(border.PassAs<views::Border>());
806 }
807 AddChildView(logout_button_);
808 }
809
810 void UserView::AddUserCard(SystemTrayItem* owner, user::LoginStatus login) {
811 // Add padding around the panel.
812 SetBorder(views::Border::CreateEmptyBorder(kUserCardVerticalPadding,
813 kTrayPopupPaddingHorizontal,
814 kUserCardVerticalPadding,
815 kTrayPopupPaddingHorizontal));
816
817 if (SupportsMultiProfile() && login != user::LOGGED_IN_RETAIL_MODE) {
818 user_card_view_ = new UserCard(this, multiprofile_index_ == 0);
819 is_user_card_ = true;
820 } else {
821 user_card_view_ = new views::View();
822 is_user_card_ = false;
823 }
824
825 user_card_view_->SetLayoutManager(new views::BoxLayout(
826 views::BoxLayout::kHorizontal, 0, 0 , kTrayPopupPaddingBetweenItems));
827 AddChildViewAt(user_card_view_, 0);
828
829 if (login == user::LOGGED_IN_RETAIL_MODE) {
830 AddLoggedInRetailModeUserCardContent();
831 return;
832 }
833
834 // The entire user card should trigger hover (the inner items get disabled).
835 user_card_view_->SetEnabled(true);
836 user_card_view_->set_notify_enter_exit_on_child(true);
837
838 if (login == user::LOGGED_IN_PUBLIC) {
839 AddLoggedInPublicModeUserCardContent(owner);
840 return;
841 }
842
843 views::View* icon = CreateIconForUserCard(login);
844 user_card_view_->AddChildView(icon);
845
846 // To allow the border to start before the icon, reduce the size before and
847 // add an inset to the icon to get the spacing.
848 if (multiprofile_index_ == 0 && SupportsMultiProfile()) {
849 icon->SetBorder(views::Border::CreateEmptyBorder(
850 0, kTrayUserTileHoverBorderInset, 0, 0));
851 SetBorder(views::Border::CreateEmptyBorder(
852 kUserCardVerticalPadding,
853 kTrayPopupPaddingHorizontal - kTrayUserTileHoverBorderInset,
854 kUserCardVerticalPadding,
855 kTrayPopupPaddingHorizontal));
856 }
857 SessionStateDelegate* delegate =
858 Shell::GetInstance()->session_state_delegate();
859 views::Label* username = NULL;
860 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
861 if (!multiprofile_index_) {
862 base::string16 user_name_string =
863 login == user::LOGGED_IN_GUEST ?
864 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL) :
865 delegate->GetUserDisplayName(multiprofile_index_);
866 if (!user_name_string.empty()) {
867 username = new views::Label(user_name_string);
868 username->SetHorizontalAlignment(gfx::ALIGN_LEFT);
869 }
870 }
871
872 views::Label* additional = NULL;
873 if (login != user::LOGGED_IN_GUEST) {
874 base::string16 user_email_string =
875 login == user::LOGGED_IN_LOCALLY_MANAGED ?
876 bundle.GetLocalizedString(
877 IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL) :
878 base::UTF8ToUTF16(delegate->GetUserEmail(multiprofile_index_));
879 if (!user_email_string.empty()) {
880 additional = new views::Label(user_email_string);
881 additional->SetFontList(
882 bundle.GetFontList(ui::ResourceBundle::SmallFont));
883 additional->SetHorizontalAlignment(gfx::ALIGN_LEFT);
884 }
885 }
886
887 // Adjust text properties dependent on if it is an active or inactive user.
888 if (multiprofile_index_) {
889 // Fade the text of non active users to 50%.
890 SkColor text_color = additional->enabled_color();
891 text_color = SkColorSetA(text_color, SkColorGetA(text_color) / 2);
892 if (additional)
893 additional->SetDisabledColor(text_color);
894 if (username)
895 username->SetDisabledColor(text_color);
896 }
897
898 if (additional && username) {
899 views::View* details = new views::View;
900 details->SetLayoutManager(new views::BoxLayout(
901 views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0));
902 details->AddChildView(username);
903 details->AddChildView(additional);
904 user_card_view_->AddChildView(details);
905 } else {
906 if (username)
907 user_card_view_->AddChildView(username);
908 if (additional)
909 user_card_view_->AddChildView(additional);
910 }
911 }
912
913 views::View* UserView::CreateIconForUserCard(user::LoginStatus login) {
914 RoundedImageView* icon = new RoundedImageView(kProfileRoundedCornerRadius,
915 multiprofile_index_ == 0);
916 icon->SetEnabled(false);
917 if (login == user::LOGGED_IN_GUEST) {
918 icon->SetImage(*ui::ResourceBundle::GetSharedInstance().
919 GetImageNamed(IDR_AURA_UBER_TRAY_GUEST_ICON).ToImageSkia(),
920 gfx::Size(kUserIconSize, kUserIconSize));
921 } else {
922 SessionStateDelegate* delegate =
923 Shell::GetInstance()->session_state_delegate();
924 content::BrowserContext* context = delegate->GetBrowserContextByIndex(
925 multiprofile_index_);
926 icon->SetImage(delegate->GetUserImage(context),
927 gfx::Size(kUserIconSize, kUserIconSize));
928 }
929 return icon;
930 }
931
932 void UserView::AddLoggedInRetailModeUserCardContent() {
933 views::Label* details = new views::Label;
934 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
935 details->SetText(
936 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL));
937 details->SetBorder(views::Border::CreateEmptyBorder(0, 4, 0, 1));
938 details->SetHorizontalAlignment(gfx::ALIGN_LEFT);
939 user_card_view_->AddChildView(details);
940 }
941
942 void UserView::AddLoggedInPublicModeUserCardContent(SystemTrayItem* owner) {
943 user_card_view_->AddChildView(CreateIconForUserCard(user::LOGGED_IN_PUBLIC));
944 user_card_view_->AddChildView(new PublicAccountUserDetails(
945 owner, GetPreferredSize().width() + kTrayPopupPaddingBetweenItems));
946 }
947
948 void UserView::ToggleAddUserMenuOption() {
949 if (add_menu_option_.get()) {
950 popup_message_.reset();
951 mouse_watcher_.reset();
952 add_menu_option_.reset();
953 return;
954 }
955
956 // Note: We do not need to install a global event handler to delete this
957 // item since it will destroyed automatically before the menu / user menu item
958 // gets destroyed..
959 const SessionStateDelegate* session_state_delegate =
960 Shell::GetInstance()->session_state_delegate();
961 add_user_visible_but_disabled_ =
962 session_state_delegate->NumberOfLoggedInUsers() >=
963 session_state_delegate->GetMaximumNumberOfLoggedInUsers();
964 add_menu_option_.reset(new views::Widget);
965 views::Widget::InitParams params;
966 params.type = views::Widget::InitParams::TYPE_TOOLTIP;
967 params.keep_on_top = true;
968 params.context = this->GetWidget()->GetNativeWindow();
969 params.accept_events = true;
970 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
971 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
972 add_menu_option_->Init(params);
973 add_menu_option_->SetOpacity(0xFF);
974 add_menu_option_->GetNativeWindow()->set_owned_by_parent(false);
975 SetShadowType(add_menu_option_->GetNativeView(),
976 wm::SHADOW_TYPE_NONE);
977
978 // Position it below our user card.
979 gfx::Rect bounds = user_card_view_->GetBoundsInScreen();
980 bounds.set_y(bounds.y() + bounds.height());
981 add_menu_option_->SetBounds(bounds);
982
983 // Show the content.
984 AddUserView* add_user_view = new AddUserView(
985 static_cast<UserCard*>(user_card_view_), this);
986 add_menu_option_->SetContentsView(add_user_view);
987 add_menu_option_->SetAlwaysOnTop(true);
988 add_menu_option_->Show();
989 if (add_user_visible_but_disabled_) {
990 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
991 popup_message_.reset(new PopupMessage(
992 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_CAPTION_CANNOT_ADD_USER),
993 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_MESSAGE_CANNOT_ADD_USER),
994 PopupMessage::ICON_WARNING,
995 add_user_view->anchor(),
996 views::BubbleBorder::TOP_LEFT,
997 gfx::Size(parent()->bounds().width() - kPopupMessageOffset, 0),
998 2 * kPopupMessageOffset));
999 }
1000 // Find the screen area which encloses both elements and sets then a mouse
1001 // watcher which will close the "menu".
1002 gfx::Rect area = user_card_view_->GetBoundsInScreen();
1003 area.set_height(2 * area.height());
1004 mouse_watcher_.reset(new views::MouseWatcher(
1005 new UserViewMouseWatcherHost(area),
1006 this));
1007 mouse_watcher_->Start();
1008 }
1009
1010 bool UserView::SupportsMultiProfile() {
1011 // We do not want to see any multi profile additions to a user view when the
1012 // log in screen is shown.
1013 return Shell::GetInstance()->delegate()->IsMultiProfilesEnabled() &&
1014 !Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked();
1015 }
1016
1017 AddUserView::AddUserView(UserCard* owner, views::ButtonListener* listener)
1018 : CustomButton(listener),
1019 add_user_(NULL),
1020 listener_(listener),
1021 owner_(owner),
1022 anchor_(NULL) {
1023 AddContent();
1024 owner_->ForceBorderVisible(true);
1025 }
1026
1027 AddUserView::~AddUserView() {
1028 owner_->ForceBorderVisible(false);
1029 }
1030
1031 gfx::Size AddUserView::GetPreferredSize() {
1032 return owner_->bounds().size();
1033 }
1034
1035 int AddUserView::GetHeightForWidth(int width) {
1036 return owner_->bounds().size().height();
1037 }
1038
1039 void AddUserView::Layout() {
1040 gfx::Rect contents_area(GetContentsBounds());
1041 add_user_->SetBoundsRect(contents_area);
1042 }
1043
1044 void AddUserView::ButtonPressed(views::Button* sender, const ui::Event& event) {
1045 if (add_user_ == sender)
1046 listener_->ButtonPressed(this, event);
1047 else
1048 NOTREACHED();
1049 }
1050
1051 void AddUserView::AddContent() {
1052 set_notify_enter_exit_on_child(true);
1053
1054 const SessionStateDelegate* delegate =
1055 Shell::GetInstance()->session_state_delegate();
1056 bool enable = delegate->NumberOfLoggedInUsers() <
1057 delegate->GetMaximumNumberOfLoggedInUsers();
1058
1059 SetLayoutManager(new views::FillLayout());
1060 set_background(views::Background::CreateSolidBackground(kBackgroundColor));
1061
1062 // Add padding around the panel.
1063 SetBorder(views::Border::CreateSolidBorder(1, kBorderColor));
1064
1065 add_user_ = new UserCard(this, enable);
1066 add_user_->SetBorder(views::Border::CreateEmptyBorder(
1067 kUserCardVerticalPadding,
1068 kTrayPopupPaddingHorizontal - kTrayUserTileHoverBorderInset,
1069 kUserCardVerticalPadding,
1070 kTrayPopupPaddingHorizontal - kTrayUserTileHoverBorderInset));
1071
1072 add_user_->SetLayoutManager(new views::BoxLayout(
1073 views::BoxLayout::kHorizontal, 0, 0 , kTrayPopupPaddingBetweenItems));
1074 AddChildViewAt(add_user_, 0);
1075
1076 // Add the [+] icon which is also the anchor for messages.
1077 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
1078 RoundedImageView* icon = new RoundedImageView(kProfileRoundedCornerRadius,
1079 true);
1080 anchor_ = icon;
1081 icon->SetImage(*ui::ResourceBundle::GetSharedInstance().
1082 GetImageNamed(IDR_AURA_UBER_TRAY_ADD_MULTIPROFILE_USER).ToImageSkia(),
1083 gfx::Size(kUserIconSize, kUserIconSize));
1084 add_user_->AddChildView(icon);
1085
1086 // Add the command text.
1087 views::Label* command_label = new views::Label(
1088 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_SIGN_IN_ANOTHER_ACCOUNT));
1089 command_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1090 add_user_->AddChildView(command_label);
1091 }
1092
1093 } // namespace tray
1094 42
1095 TrayUser::TrayUser(SystemTray* system_tray, MultiProfileIndex index) 43 TrayUser::TrayUser(SystemTray* system_tray, MultiProfileIndex index)
1096 : SystemTrayItem(system_tray), 44 : SystemTrayItem(system_tray),
1097 multiprofile_index_(index), 45 multiprofile_index_(index),
1098 user_(NULL), 46 user_(NULL),
1099 layout_view_(NULL), 47 layout_view_(NULL),
1100 avatar_(NULL), 48 avatar_(NULL),
1101 label_(NULL) { 49 label_(NULL) {
1102 Shell::GetInstance()->system_tray_notifier()->AddUserObserver(this); 50 Shell::GetInstance()->system_tray_notifier()->AddUserObserver(this);
1103 } 51 }
(...skipping 21 matching lines...) Expand all
1125 return user_->GetBoundsInScreenOfUserButtonForTest(); 73 return user_->GetBoundsInScreenOfUserButtonForTest();
1126 } 74 }
1127 75
1128 void TrayUser::UpdateAfterLoginStatusChangeForTest(user::LoginStatus status) { 76 void TrayUser::UpdateAfterLoginStatusChangeForTest(user::LoginStatus status) {
1129 UpdateAfterLoginStatusChange(status); 77 UpdateAfterLoginStatusChange(status);
1130 } 78 }
1131 79
1132 views::View* TrayUser::CreateTrayView(user::LoginStatus status) { 80 views::View* TrayUser::CreateTrayView(user::LoginStatus status) {
1133 CHECK(layout_view_ == NULL); 81 CHECK(layout_view_ == NULL);
1134 82
1135 layout_view_ = new views::View(); 83 layout_view_ = new views::View;
1136 layout_view_->SetLayoutManager( 84 layout_view_->SetLayoutManager(
1137 new views::BoxLayout(views::BoxLayout::kHorizontal, 85 new views::BoxLayout(views::BoxLayout::kHorizontal,
1138 0, 0, kUserLabelToIconPadding)); 86 0, 0, kUserLabelToIconPadding));
1139 UpdateAfterLoginStatusChange(status); 87 UpdateAfterLoginStatusChange(status);
1140 return layout_view_; 88 return layout_view_;
1141 } 89 }
1142 90
1143 views::View* TrayUser::CreateDefaultView(user::LoginStatus status) { 91 views::View* TrayUser::CreateDefaultView(user::LoginStatus status) {
1144 if (status == user::LOGGED_IN_NONE) 92 if (status == user::LOGGED_IN_NONE)
1145 return NULL; 93 return NULL;
1146 const SessionStateDelegate* session_state_delegate = 94 const SessionStateDelegate* session_state_delegate =
1147 Shell::GetInstance()->session_state_delegate(); 95 Shell::GetInstance()->session_state_delegate();
1148 96
1149 // If the screen is locked show only the currently active user. 97 // If the screen is locked show only the currently active user.
1150 if (multiprofile_index_ && session_state_delegate->IsUserSessionBlocked()) 98 if (multiprofile_index_ && session_state_delegate->IsUserSessionBlocked())
1151 return NULL; 99 return NULL;
1152 100
1153 CHECK(user_ == NULL); 101 CHECK(user_ == NULL);
1154 102
1155 int logged_in_users = session_state_delegate->NumberOfLoggedInUsers(); 103 int logged_in_users = session_state_delegate->NumberOfLoggedInUsers();
1156 104
1157 // Do not show more UserView's then there are logged in users. 105 // Do not show more UserView's then there are logged in users.
1158 if (multiprofile_index_ >= logged_in_users) 106 if (multiprofile_index_ >= logged_in_users)
1159 return NULL; 107 return NULL;
1160 108
1161 user_ = new tray::UserView(this, status, multiprofile_index_); 109 user_ = new tray::UserView(this, status, multiprofile_index_, false);
1162 return user_; 110 return user_;
1163 } 111 }
1164 112
1165 views::View* TrayUser::CreateDetailedView(user::LoginStatus status) { 113 views::View* TrayUser::CreateDetailedView(user::LoginStatus status) {
1166 return NULL; 114 return new tray::AccountsDetailedView(this, status);
1167 } 115 }
1168 116
1169 void TrayUser::DestroyTrayView() { 117 void TrayUser::DestroyTrayView() {
1170 layout_view_ = NULL; 118 layout_view_ = NULL;
1171 avatar_ = NULL; 119 avatar_ = NULL;
1172 label_ = NULL; 120 label_ = NULL;
1173 } 121 }
1174 122
1175 void TrayUser::DestroyDefaultView() { 123 void TrayUser::DestroyDefaultView() {
1176 user_ = NULL; 124 user_ = NULL;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1211 (need_label != (label_ != NULL))) { 159 (need_label != (label_ != NULL))) {
1212 layout_view_->RemoveAllChildViews(true); 160 layout_view_->RemoveAllChildViews(true);
1213 if (need_label) { 161 if (need_label) {
1214 label_ = new views::Label; 162 label_ = new views::Label;
1215 SetupLabelForTray(label_); 163 SetupLabelForTray(label_);
1216 layout_view_->AddChildView(label_); 164 layout_view_->AddChildView(label_);
1217 } else { 165 } else {
1218 label_ = NULL; 166 label_ = NULL;
1219 } 167 }
1220 if (need_avatar) { 168 if (need_avatar) {
1221 avatar_ = new tray::RoundedImageView(kProfileRoundedCornerRadius, true); 169 avatar_ = new tray::RoundedImageView(kTrayAvatarCornerRadius, true);
1222 layout_view_->AddChildView(avatar_); 170 layout_view_->AddChildView(avatar_);
1223 } else { 171 } else {
1224 avatar_ = NULL; 172 avatar_ = NULL;
1225 } 173 }
1226 } 174 }
1227 175
1228 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
1229 if (status == user::LOGGED_IN_LOCALLY_MANAGED) { 176 if (status == user::LOGGED_IN_LOCALLY_MANAGED) {
1230 label_->SetText( 177 label_->SetText(
1231 bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL)); 178 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL));
1232 } else if (status == user::LOGGED_IN_GUEST) { 179 } else if (status == user::LOGGED_IN_GUEST) {
1233 label_->SetText(bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL)); 180 label_->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL));
1234 } 181 }
1235 182
1236 if (avatar_ && switches::UseAlternateShelfLayout()) { 183 if (avatar_ && switches::UseAlternateShelfLayout()) {
1237 avatar_->SetCornerRadii( 184 avatar_->SetCornerRadii(
1238 0, kUserIconLargeCornerRadius, kUserIconLargeCornerRadius, 0); 185 0, kTrayAvatarLargeCornerRadius, kTrayAvatarLargeCornerRadius, 0);
1239 avatar_->SetBorder(views::Border::NullBorder()); 186 avatar_->SetBorder(views::Border::NullBorder());
1240 } 187 }
1241 UpdateAvatarImage(status); 188 UpdateAvatarImage(status);
1242 189
1243 // Update layout after setting label_ and avatar_ with new login status. 190 // Update layout after setting label_ and avatar_ with new login status.
1244 UpdateLayoutOfItem(); 191 UpdateLayoutOfItem();
1245 } 192 }
1246 193
1247 void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { 194 void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
1248 // Inactive users won't have a layout. 195 // Inactive users won't have a layout.
1249 if (!layout_view_) 196 if (!layout_view_)
1250 return; 197 return;
1251 if (alignment == SHELF_ALIGNMENT_BOTTOM || 198 if (alignment == SHELF_ALIGNMENT_BOTTOM ||
1252 alignment == SHELF_ALIGNMENT_TOP) { 199 alignment == SHELF_ALIGNMENT_TOP) {
1253 if (avatar_) { 200 if (avatar_) {
1254 if (switches::UseAlternateShelfLayout()) { 201 if (switches::UseAlternateShelfLayout()) {
1255 avatar_->SetBorder(views::Border::NullBorder()); 202 avatar_->SetBorder(views::Border::NullBorder());
1256 avatar_->SetCornerRadii( 203 avatar_->SetCornerRadii(
1257 0, kUserIconLargeCornerRadius, kUserIconLargeCornerRadius, 0); 204 0, kTrayAvatarLargeCornerRadius, kTrayAvatarLargeCornerRadius, 0);
1258 } else { 205 } else {
1259 avatar_->SetBorder(views::Border::CreateEmptyBorder( 206 avatar_->SetBorder(views::Border::CreateEmptyBorder(
1260 0, 207 0,
1261 kTrayImageItemHorizontalPaddingBottomAlignment + 2, 208 kTrayImageItemHorizontalPaddingBottomAlignment + 2,
1262 0, 209 0,
1263 kTrayImageItemHorizontalPaddingBottomAlignment)); 210 kTrayImageItemHorizontalPaddingBottomAlignment));
1264 } 211 }
1265 } 212 }
1266 if (label_) { 213 if (label_) {
1267 // If label_ hasn't figured out its size yet, do that first. 214 // If label_ hasn't figured out its size yet, do that first.
1268 if (label_->GetContentsBounds().height() == 0) 215 if (label_->GetContentsBounds().height() == 0)
1269 label_->SizeToPreferredSize(); 216 label_->SizeToPreferredSize();
1270 int height = label_->GetContentsBounds().height(); 217 int height = label_->GetContentsBounds().height();
1271 int vertical_pad = (kTrayItemSize - height) / 2; 218 int vertical_pad = (kTrayItemSize - height) / 2;
1272 int remainder = height % 2; 219 int remainder = height % 2;
1273 label_->SetBorder(views::Border::CreateEmptyBorder( 220 label_->SetBorder(views::Border::CreateEmptyBorder(
1274 vertical_pad + remainder, 221 vertical_pad + remainder,
1275 kTrayLabelItemHorizontalPaddingBottomAlignment, 222 kTrayLabelItemHorizontalPaddingBottomAlignment,
1276 vertical_pad, 223 vertical_pad,
1277 kTrayLabelItemHorizontalPaddingBottomAlignment)); 224 kTrayLabelItemHorizontalPaddingBottomAlignment));
1278 } 225 }
1279 layout_view_->SetLayoutManager( 226 layout_view_->SetLayoutManager(
1280 new views::BoxLayout(views::BoxLayout::kHorizontal, 227 new views::BoxLayout(views::BoxLayout::kHorizontal,
1281 0, 0, kUserLabelToIconPadding)); 228 0, 0, kUserLabelToIconPadding));
1282 } else { 229 } else {
1283 if (avatar_) { 230 if (avatar_) {
1284 if (switches::UseAlternateShelfLayout()) { 231 if (switches::UseAlternateShelfLayout()) {
1285 avatar_->SetBorder(views::Border::NullBorder()); 232 avatar_->SetBorder(views::Border::NullBorder());
1286 avatar_->SetCornerRadii( 233 avatar_->SetCornerRadii(
1287 0, 0, kUserIconLargeCornerRadius, kUserIconLargeCornerRadius); 234 0, 0, kTrayAvatarLargeCornerRadius, kTrayAvatarLargeCornerRadius);
1288 } else { 235 } else {
1289 SetTrayImageItemBorder(avatar_, alignment); 236 SetTrayImageItemBorder(avatar_, alignment);
1290 } 237 }
1291 } 238 }
1292 if (label_) { 239 if (label_) {
1293 label_->SetBorder(views::Border::CreateEmptyBorder( 240 label_->SetBorder(views::Border::CreateEmptyBorder(
1294 kTrayLabelItemVerticalPaddingVerticalAlignment, 241 kTrayLabelItemVerticalPaddingVerticalAlignment,
1295 kTrayLabelItemHorizontalPaddingBottomAlignment, 242 kTrayLabelItemHorizontalPaddingBottomAlignment,
1296 kTrayLabelItemVerticalPaddingVerticalAlignment, 243 kTrayLabelItemVerticalPaddingVerticalAlignment,
1297 kTrayLabelItemHorizontalPaddingBottomAlignment)); 244 kTrayLabelItemHorizontalPaddingBottomAlignment));
(...skipping 24 matching lines...) Expand all
1322 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus()); 269 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus());
1323 } 270 }
1324 271
1325 void TrayUser::UpdateAvatarImage(user::LoginStatus status) { 272 void TrayUser::UpdateAvatarImage(user::LoginStatus status) {
1326 SessionStateDelegate* session_state_delegate = 273 SessionStateDelegate* session_state_delegate =
1327 Shell::GetInstance()->session_state_delegate(); 274 Shell::GetInstance()->session_state_delegate();
1328 if (!avatar_ || 275 if (!avatar_ ||
1329 GetTrayIndex() >= session_state_delegate->NumberOfLoggedInUsers()) 276 GetTrayIndex() >= session_state_delegate->NumberOfLoggedInUsers())
1330 return; 277 return;
1331 278
1332 int icon_size = switches::UseAlternateShelfLayout() ? 279 int icon_size = switches::UseAlternateShelfLayout() ? kTrayAvatarLargeSize
1333 kUserIconLargeSize : kUserIconSize; 280 : kTrayAvatarSize;
1334 281
1335 content::BrowserContext* context = session_state_delegate-> 282 content::BrowserContext* context = session_state_delegate->
1336 GetBrowserContextByIndex(GetTrayIndex()); 283 GetBrowserContextByIndex(GetTrayIndex());
1337 avatar_->SetImage(session_state_delegate->GetUserImage(context), 284 avatar_->SetImage(session_state_delegate->GetUserImage(context),
1338 gfx::Size(icon_size, icon_size)); 285 gfx::Size(icon_size, icon_size));
1339 286
1340 // Unit tests might come here with no images for some users. 287 // Unit tests might come here with no images for some users.
1341 if (avatar_->size().IsEmpty()) 288 if (avatar_->size().IsEmpty())
1342 avatar_->SetSize(gfx::Size(icon_size, icon_size)); 289 avatar_->SetSize(gfx::Size(icon_size, icon_size));
1343 } 290 }
(...skipping 12 matching lines...) Expand all
1356 void TrayUser::UpdateLayoutOfItem() { 303 void TrayUser::UpdateLayoutOfItem() {
1357 RootWindowController* controller = GetRootWindowController( 304 RootWindowController* controller = GetRootWindowController(
1358 system_tray()->GetWidget()->GetNativeWindow()->GetRootWindow()); 305 system_tray()->GetWidget()->GetNativeWindow()->GetRootWindow());
1359 if (controller && controller->shelf()) { 306 if (controller && controller->shelf()) {
1360 UpdateAfterShelfAlignmentChange( 307 UpdateAfterShelfAlignmentChange(
1361 controller->GetShelfLayoutManager()->GetAlignment()); 308 controller->GetShelfLayoutManager()->GetAlignment());
1362 } 309 }
1363 } 310 }
1364 311
1365 } // namespace ash 312 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/user/tray_user.h ('k') | ash/system/user/user_accounts_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698