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

Side by Side Diff: ash/system/tray/system_tray.cc

Issue 2148593004: mash: Move StatusTray and StatusAreaWidget to //ash/common (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@traydisplay
Patch Set: rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ash/system/tray/system_tray.h ('k') | ash/system/tray/system_tray_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "ash/system/tray/system_tray.h"
6
7 #include "ash/common/ash_switches.h"
8 #include "ash/common/login_status.h"
9 #include "ash/common/session/session_state_delegate.h"
10 #include "ash/common/shelf/wm_shelf.h"
11 #include "ash/common/shelf/wm_shelf_util.h"
12 #include "ash/common/shell_window_ids.h"
13 #include "ash/common/system/cast/tray_cast.h"
14 #include "ash/common/system/date/tray_date.h"
15 #include "ash/common/system/tray/system_tray_delegate.h"
16 #include "ash/common/system/tray/system_tray_item.h"
17 #include "ash/common/system/tray/tray_bubble_wrapper.h"
18 #include "ash/common/system/tray/tray_constants.h"
19 #include "ash/common/system/tray_accessibility.h"
20 #include "ash/common/system/update/tray_update.h"
21 #include "ash/common/system/user/tray_user.h"
22 #include "ash/common/system/user/tray_user_separator.h"
23 #include "ash/common/system/web_notification/web_notification_tray.h"
24 #include "ash/common/wm_lookup.h"
25 #include "ash/common/wm_root_window_controller.h"
26 #include "ash/common/wm_shell.h"
27 #include "ash/common/wm_window.h"
28 #include "base/logging.h"
29 #include "base/metrics/histogram.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "base/timer/timer.h"
32 #include "grit/ash_strings.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/compositor/layer.h"
35 #include "ui/display/display.h"
36 #include "ui/display/screen.h"
37 #include "ui/events/event_constants.h"
38 #include "ui/gfx/canvas.h"
39 #include "ui/gfx/skia_util.h"
40 #include "ui/views/border.h"
41 #include "ui/views/controls/label.h"
42 #include "ui/views/layout/box_layout.h"
43 #include "ui/views/layout/fill_layout.h"
44 #include "ui/views/view.h"
45
46 #if defined(OS_CHROMEOS)
47 #include "ash/common/system/chromeos/audio/tray_audio_chromeos.h"
48 #include "ash/common/system/chromeos/bluetooth/tray_bluetooth.h"
49 #include "ash/common/system/chromeos/brightness/tray_brightness.h"
50 #include "ash/common/system/chromeos/enterprise/tray_enterprise.h"
51 #include "ash/common/system/chromeos/media_security/multi_profile_media_tray_ite m.h"
52 #include "ash/common/system/chromeos/network/tray_network.h"
53 #include "ash/common/system/chromeos/network/tray_sms.h"
54 #include "ash/common/system/chromeos/network/tray_vpn.h"
55 #include "ash/common/system/chromeos/power/power_status.h"
56 #include "ash/common/system/chromeos/power/tray_power.h"
57 #include "ash/common/system/chromeos/screen_security/screen_capture_tray_item.h"
58 #include "ash/common/system/chromeos/screen_security/screen_share_tray_item.h"
59 #include "ash/common/system/chromeos/session/tray_session_length_limit.h"
60 #include "ash/common/system/chromeos/settings/tray_settings.h"
61 #include "ash/common/system/chromeos/supervised/tray_supervised_user.h"
62 #include "ash/common/system/chromeos/tray_caps_lock.h"
63 #include "ash/common/system/chromeos/tray_tracing.h"
64 #include "ash/common/system/ime/tray_ime_chromeos.h"
65 #include "ui/message_center/message_center.h"
66 #endif
67
68 using views::TrayBubbleView;
69
70 namespace ash {
71
72 // The minimum width of the system tray menu width.
73 const int kMinimumSystemTrayMenuWidth = 300;
74
75 // Class to initialize and manage the SystemTrayBubble and TrayBubbleWrapper
76 // instances for a bubble.
77
78 class SystemBubbleWrapper {
79 public:
80 // Takes ownership of |bubble|.
81 explicit SystemBubbleWrapper(SystemTrayBubble* bubble)
82 : bubble_(bubble), is_persistent_(false) {}
83
84 // Initializes the bubble view and creates |bubble_wrapper_|.
85 void InitView(TrayBackgroundView* tray,
86 views::View* anchor,
87 TrayBubbleView::InitParams* init_params,
88 bool is_persistent) {
89 DCHECK(anchor);
90 LoginStatus login_status =
91 WmShell::Get()->system_tray_delegate()->GetUserLoginStatus();
92 bubble_->InitView(anchor, login_status, init_params);
93 bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_->bubble_view()));
94 // The system bubble should not have an arrow.
95 bubble_->bubble_view()->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
96 is_persistent_ = is_persistent;
97
98 // If ChromeVox is enabled, focus the default item if no item is focused and
99 // there isn't a delayed close.
100 if (WmShell::Get()->GetAccessibilityDelegate()->IsSpokenFeedbackEnabled() &&
101 !is_persistent) {
102 bubble_->FocusDefaultIfNeeded();
103 }
104 }
105
106 // Convenience accessors:
107 SystemTrayBubble* bubble() const { return bubble_.get(); }
108 SystemTrayBubble::BubbleType bubble_type() const {
109 return bubble_->bubble_type();
110 }
111 TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); }
112 bool is_persistent() const { return is_persistent_; }
113
114 private:
115 std::unique_ptr<SystemTrayBubble> bubble_;
116 std::unique_ptr<TrayBubbleWrapper> bubble_wrapper_;
117 bool is_persistent_;
118
119 DISALLOW_COPY_AND_ASSIGN(SystemBubbleWrapper);
120 };
121
122 // SystemTray
123
124 SystemTray::SystemTray(WmShelf* wm_shelf)
125 : TrayBackgroundView(wm_shelf),
126 web_notification_tray_(nullptr),
127 detailed_item_(nullptr),
128 default_bubble_height_(0),
129 hide_notifications_(false),
130 full_system_tray_menu_(false),
131 tray_accessibility_(nullptr),
132 tray_cast_(nullptr),
133 tray_date_(nullptr),
134 tray_update_(nullptr),
135 screen_capture_tray_item_(nullptr),
136 screen_share_tray_item_(nullptr) {
137 SetContentsBackground();
138 }
139
140 SystemTray::~SystemTray() {
141 // Destroy any child views that might have back pointers before ~View().
142 system_bubble_.reset();
143 notification_bubble_.reset();
144 for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
145 it != items_.end(); ++it) {
146 (*it)->DestroyTrayView();
147 }
148 }
149
150 void SystemTray::InitializeTrayItems(
151 SystemTrayDelegate* delegate,
152 WebNotificationTray* web_notification_tray) {
153 DCHECK(web_notification_tray);
154 web_notification_tray_ = web_notification_tray;
155 TrayBackgroundView::Initialize();
156 CreateItems(delegate);
157 }
158
159 void SystemTray::Shutdown() {
160 DCHECK(web_notification_tray_);
161 web_notification_tray_ = nullptr;
162 }
163
164 void SystemTray::CreateItems(SystemTrayDelegate* delegate) {
165 WmShell* wm_shell = WmShell::Get();
166 #if !defined(OS_WIN)
167 // Create user items for each possible user.
168 int maximum_user_profiles =
169 wm_shell->GetSessionStateDelegate()->GetMaximumNumberOfLoggedInUsers();
170 for (int i = 0; i < maximum_user_profiles; i++)
171 AddTrayItem(new TrayUser(this, i));
172
173 if (maximum_user_profiles > 1) {
174 // Add a special double line separator between users and the rest of the
175 // menu if more then one user is logged in.
176 AddTrayItem(new TrayUserSeparator(this));
177 }
178 #endif
179
180 tray_accessibility_ = new TrayAccessibility(this);
181 tray_date_ = new TrayDate(this);
182 tray_update_ = new TrayUpdate(this);
183
184 #if defined(OS_CHROMEOS)
185 AddTrayItem(new TraySessionLengthLimit(this));
186 AddTrayItem(new TrayEnterprise(this));
187 AddTrayItem(new TraySupervisedUser(this));
188 AddTrayItem(new TrayIME(this));
189 AddTrayItem(tray_accessibility_);
190 AddTrayItem(new TrayTracing(this));
191 AddTrayItem(new TrayPower(this, message_center::MessageCenter::Get()));
192 AddTrayItem(new TrayNetwork(this));
193 AddTrayItem(new TrayVPN(this));
194 AddTrayItem(new TraySms(this));
195 AddTrayItem(new TrayBluetooth(this));
196 tray_cast_ = new TrayCast(this);
197 AddTrayItem(tray_cast_);
198 // TODO(jamescook): Remove this when mus has support for display management
199 // and we have a DisplayManager equivalent. See http://crbug.com/548429
200 std::unique_ptr<SystemTrayItem> tray_display =
201 delegate->CreateDisplayTrayItem(this);
202 if (tray_display)
203 AddTrayItem(tray_display.release());
204 screen_capture_tray_item_ = new ScreenCaptureTrayItem(this);
205 AddTrayItem(screen_capture_tray_item_);
206 screen_share_tray_item_ = new ScreenShareTrayItem(this);
207 AddTrayItem(screen_share_tray_item_);
208 AddTrayItem(new MultiProfileMediaTrayItem(this));
209 AddTrayItem(new TrayAudioChromeOs(this));
210 AddTrayItem(new TrayBrightness(this));
211 AddTrayItem(new TrayCapsLock(this));
212 // TODO(jamescook): Remove this when mus has support for display management
213 // and we have a DisplayManager equivalent. See http://crbug.com/548429
214 std::unique_ptr<SystemTrayItem> tray_rotation_lock =
215 delegate->CreateRotationLockTrayItem(this);
216 if (tray_rotation_lock)
217 AddTrayItem(tray_rotation_lock.release());
218 AddTrayItem(new TraySettings(this));
219 AddTrayItem(tray_update_);
220 AddTrayItem(tray_date_);
221 #elif defined(OS_WIN)
222 AddTrayItem(tray_accessibility_);
223 AddTrayItem(tray_update_);
224 AddTrayItem(tray_date_);
225 #endif
226
227 SetVisible(wm_shell->system_tray_delegate()->GetTrayVisibilityOnStartup());
228 }
229
230 void SystemTray::AddTrayItem(SystemTrayItem* item) {
231 items_.push_back(item);
232
233 SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate();
234 views::View* tray_item = item->CreateTrayView(delegate->GetUserLoginStatus());
235 item->UpdateAfterShelfAlignmentChange(shelf_alignment());
236
237 if (tray_item) {
238 tray_container()->AddChildViewAt(tray_item, 0);
239 PreferredSizeChanged();
240 tray_item_map_[item] = tray_item;
241 }
242 }
243
244 const std::vector<SystemTrayItem*>& SystemTray::GetTrayItems() const {
245 return items_.get();
246 }
247
248 void SystemTray::ShowDefaultView(BubbleCreationType creation_type) {
249 ShowDefaultViewWithOffset(
250 creation_type, TrayBubbleView::InitParams::kArrowDefaultOffset, false);
251 }
252
253 void SystemTray::ShowPersistentDefaultView() {
254 ShowItems(items_.get(), false, false, BUBBLE_CREATE_NEW,
255 TrayBubbleView::InitParams::kArrowDefaultOffset, true);
256 }
257
258 void SystemTray::ShowDetailedView(SystemTrayItem* item,
259 int close_delay,
260 bool activate,
261 BubbleCreationType creation_type) {
262 std::vector<SystemTrayItem*> items;
263 // The detailed view with timeout means a UI to show the current system state,
264 // like the audio level or brightness. Such UI should behave as persistent and
265 // keep its own logic for the appearance.
266 bool persistent =
267 (!activate && close_delay > 0 && creation_type == BUBBLE_CREATE_NEW);
268 items.push_back(item);
269 ShowItems(items, true, activate, creation_type, GetTrayXOffset(item),
270 persistent);
271 if (system_bubble_)
272 system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
273 }
274
275 void SystemTray::SetDetailedViewCloseDelay(int close_delay) {
276 if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DETAILED))
277 system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
278 }
279
280 void SystemTray::HideDetailedView(SystemTrayItem* item) {
281 if (item != detailed_item_)
282 return;
283 DestroySystemBubble();
284 UpdateNotificationBubble();
285 }
286
287 void SystemTray::ShowNotificationView(SystemTrayItem* item) {
288 if (std::find(notification_items_.begin(), notification_items_.end(), item) !=
289 notification_items_.end())
290 return;
291 notification_items_.push_back(item);
292 UpdateNotificationBubble();
293 }
294
295 void SystemTray::HideNotificationView(SystemTrayItem* item) {
296 std::vector<SystemTrayItem*>::iterator found_iter =
297 std::find(notification_items_.begin(), notification_items_.end(), item);
298 if (found_iter == notification_items_.end())
299 return;
300 notification_items_.erase(found_iter);
301 // Only update the notification bubble if visible (i.e. don't create one).
302 if (notification_bubble_)
303 UpdateNotificationBubble();
304 }
305
306 void SystemTray::UpdateAfterLoginStatusChange(LoginStatus login_status) {
307 DestroySystemBubble();
308 UpdateNotificationBubble();
309
310 for (SystemTrayItem* item : items_)
311 item->UpdateAfterLoginStatusChange(login_status);
312
313 // Items default to SHELF_ALIGNMENT_BOTTOM. Update them if the initial
314 // position of the shelf differs.
315 if (!IsHorizontalAlignment(shelf_alignment()))
316 UpdateAfterShelfAlignmentChange(shelf_alignment());
317
318 SetVisible(true);
319 PreferredSizeChanged();
320 }
321
322 void SystemTray::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
323 for (SystemTrayItem* item : items_)
324 item->UpdateAfterShelfAlignmentChange(alignment);
325 }
326
327 void SystemTray::SetHideNotifications(bool hide_notifications) {
328 if (notification_bubble_)
329 notification_bubble_->bubble()->SetVisible(!hide_notifications);
330 hide_notifications_ = hide_notifications;
331 }
332
333 bool SystemTray::ShouldShowShelf() const {
334 return system_bubble_.get() && system_bubble_->bubble()->ShouldShowShelf();
335 }
336
337 bool SystemTray::HasSystemBubble() const {
338 return system_bubble_.get() != NULL;
339 }
340
341 bool SystemTray::HasNotificationBubble() const {
342 return notification_bubble_.get() != NULL;
343 }
344
345 SystemTrayBubble* SystemTray::GetSystemBubble() {
346 if (!system_bubble_)
347 return NULL;
348 return system_bubble_->bubble();
349 }
350
351 bool SystemTray::IsAnyBubbleVisible() const {
352 return ((system_bubble_.get() && system_bubble_->bubble()->IsVisible()) ||
353 (notification_bubble_.get() &&
354 notification_bubble_->bubble()->IsVisible()));
355 }
356
357 bool SystemTray::IsMouseInNotificationBubble() const {
358 if (!notification_bubble_)
359 return false;
360 return notification_bubble_->bubble_view()->GetBoundsInScreen().Contains(
361 display::Screen::GetScreen()->GetCursorScreenPoint());
362 }
363
364 bool SystemTray::CloseSystemBubble() const {
365 if (!system_bubble_)
366 return false;
367 system_bubble_->bubble()->Close();
368 return true;
369 }
370
371 views::View* SystemTray::GetHelpButtonView() const {
372 return tray_date_->GetHelpButtonView();
373 }
374
375 bool SystemTray::CloseNotificationBubbleForTest() const {
376 if (!notification_bubble_)
377 return false;
378 notification_bubble_->bubble()->Close();
379 return true;
380 }
381
382 // Private methods.
383
384 bool SystemTray::HasSystemBubbleType(SystemTrayBubble::BubbleType type) {
385 DCHECK(type != SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION);
386 return system_bubble_.get() && system_bubble_->bubble_type() == type;
387 }
388
389 void SystemTray::DestroySystemBubble() {
390 CloseSystemBubbleAndDeactivateSystemTray();
391 detailed_item_ = NULL;
392 UpdateWebNotifications();
393 }
394
395 void SystemTray::DestroyNotificationBubble() {
396 if (notification_bubble_) {
397 notification_bubble_.reset();
398 UpdateWebNotifications();
399 }
400 }
401
402 base::string16 SystemTray::GetAccessibleNameForTray() {
403 base::string16 time = GetAccessibleTimeString(base::Time::Now());
404 base::string16 battery = base::ASCIIToUTF16("");
405 #if defined(OS_CHROMEOS)
406 battery = PowerStatus::Get()->GetAccessibleNameString(false);
407 #endif
408 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBLE_DESCRIPTION,
409 time, battery);
410 }
411
412 int SystemTray::GetTrayXOffset(SystemTrayItem* item) const {
413 // Don't attempt to align the arrow if the shelf is on the left or right.
414 if (!IsHorizontalAlignment(shelf_alignment()))
415 return TrayBubbleView::InitParams::kArrowDefaultOffset;
416
417 std::map<SystemTrayItem*, views::View*>::const_iterator it =
418 tray_item_map_.find(item);
419 if (it == tray_item_map_.end())
420 return TrayBubbleView::InitParams::kArrowDefaultOffset;
421
422 const views::View* item_view = it->second;
423 if (item_view->bounds().IsEmpty()) {
424 // The bounds of item could be still empty if it does not have a visible
425 // tray view. In that case, use the default (minimum) offset.
426 return TrayBubbleView::InitParams::kArrowDefaultOffset;
427 }
428
429 gfx::Point point(item_view->width() / 2, 0);
430 ConvertPointToWidget(item_view, &point);
431 return point.x();
432 }
433
434 void SystemTray::ShowDefaultViewWithOffset(BubbleCreationType creation_type,
435 int arrow_offset,
436 bool persistent) {
437 if (creation_type != BUBBLE_USE_EXISTING)
438 WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_MENU_OPENED);
439 ShowItems(items_.get(), false, true, creation_type, arrow_offset, persistent);
440 }
441
442 void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items,
443 bool detailed,
444 bool can_activate,
445 BubbleCreationType creation_type,
446 int arrow_offset,
447 bool persistent) {
448 // No system tray bubbles in kiosk mode.
449 if (WmShell::Get()->system_tray_delegate()->GetUserLoginStatus() ==
450 LoginStatus::KIOSK_APP) {
451 return;
452 }
453
454 // Destroy any existing bubble and create a new one.
455 SystemTrayBubble::BubbleType bubble_type =
456 detailed ? SystemTrayBubble::BUBBLE_TYPE_DETAILED
457 : SystemTrayBubble::BUBBLE_TYPE_DEFAULT;
458
459 // Destroy the notification bubble here so that it doesn't get rebuilt
460 // while we add items to the main bubble_ (e.g. in HideNotificationView).
461 notification_bubble_.reset();
462 if (system_bubble_.get() && creation_type == BUBBLE_USE_EXISTING) {
463 system_bubble_->bubble()->UpdateView(items, bubble_type);
464 // If ChromeVox is enabled, focus the default item if no item is focused.
465 if (WmShell::Get()->GetAccessibilityDelegate()->IsSpokenFeedbackEnabled())
466 system_bubble_->bubble()->FocusDefaultIfNeeded();
467 } else {
468 // Cleanup the existing bubble before showing a new one. Otherwise, it's
469 // possible to confuse the new system bubble with the old one during
470 // destruction, leading to subtle errors/crashes such as crbug.com/545166.
471 DestroySystemBubble();
472
473 // Remember if the menu is a single property (like e.g. volume) or the
474 // full tray menu. Note that in case of the |BUBBLE_USE_EXISTING| case
475 // above, |full_system_tray_menu_| does not get changed since the fact that
476 // the menu is full (or not) doesn't change even if a "single property"
477 // (like network) replaces most of the menu.
478 full_system_tray_menu_ = items.size() > 1;
479 // The menu width is fixed, and it is a per language setting.
480 int menu_width = std::max(
481 kMinimumSystemTrayMenuWidth,
482 WmShell::Get()->system_tray_delegate()->GetSystemTrayMenuWidth());
483
484 TrayBubbleView::InitParams init_params(TrayBubbleView::ANCHOR_TYPE_TRAY,
485 GetAnchorAlignment(), menu_width,
486 kTrayPopupMaxWidth);
487 init_params.can_activate = can_activate;
488 init_params.first_item_has_no_margin = true;
489 if (detailed) {
490 // This is the case where a volume control or brightness control bubble
491 // is created.
492 init_params.max_height = default_bubble_height_;
493 init_params.arrow_color = kBackgroundColor;
494 } else {
495 init_params.arrow_color = kHeaderBackgroundColor;
496 }
497 init_params.arrow_offset = arrow_offset;
498 if (bubble_type == SystemTrayBubble::BUBBLE_TYPE_DEFAULT)
499 init_params.close_on_deactivate = !persistent;
500 // For Volume and Brightness we don't want to show an arrow when
501 // they are shown in a bubble by themselves.
502 init_params.arrow_paint_type = views::BubbleBorder::PAINT_NORMAL;
503 if (items.size() == 1 && items[0]->ShouldHideArrow())
504 init_params.arrow_paint_type = views::BubbleBorder::PAINT_TRANSPARENT;
505 SystemTrayBubble* bubble = new SystemTrayBubble(this, items, bubble_type);
506
507 system_bubble_.reset(new SystemBubbleWrapper(bubble));
508 system_bubble_->InitView(this, tray_container(), &init_params, persistent);
509
510 // Record metrics for the system menu when the default view is invoked.
511 if (!detailed)
512 RecordSystemMenuMetrics();
513 }
514 // Save height of default view for creating detailed views directly.
515 if (!detailed)
516 default_bubble_height_ = system_bubble_->bubble_view()->height();
517
518 if (detailed && items.size() > 0)
519 detailed_item_ = items[0];
520 else
521 detailed_item_ = NULL;
522
523 UpdateNotificationBubble(); // State changed, re-create notifications.
524 if (!notification_bubble_)
525 UpdateWebNotifications();
526 shelf()->UpdateAutoHideState();
527
528 // When we show the system menu in our alternate shelf layout, we need to
529 // tint the background.
530 if (full_system_tray_menu_)
531 SetDrawBackgroundAsActive(true);
532 }
533
534 void SystemTray::UpdateNotificationBubble() {
535 // Only show the notification bubble if we have notifications.
536 if (notification_items_.empty()) {
537 DestroyNotificationBubble();
538 return;
539 }
540 // Destroy the existing bubble before constructing a new one.
541 notification_bubble_.reset();
542 SystemTrayBubble* notification_bubble;
543 notification_bubble = new SystemTrayBubble(
544 this, notification_items_, SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION);
545 views::View* anchor;
546 TrayBubbleView::AnchorType anchor_type;
547 // Tray items might want to show notifications while we are creating and
548 // initializing the |system_bubble_| - but it might not be fully initialized
549 // when coming here - this would produce a crashed like crbug.com/247416.
550 // As such we check the existence of the widget here.
551 if (system_bubble_.get() && system_bubble_->bubble_view() &&
552 system_bubble_->bubble_view()->GetWidget()) {
553 anchor = system_bubble_->bubble_view();
554 anchor_type = TrayBubbleView::ANCHOR_TYPE_BUBBLE;
555 } else {
556 anchor = tray_container();
557 anchor_type = TrayBubbleView::ANCHOR_TYPE_TRAY;
558 }
559 TrayBubbleView::InitParams init_params(anchor_type, GetAnchorAlignment(),
560 kTrayPopupMinWidth,
561 kTrayPopupMaxWidth);
562 init_params.first_item_has_no_margin = true;
563 init_params.arrow_color = kBackgroundColor;
564 init_params.arrow_offset = GetTrayXOffset(notification_items_[0]);
565 notification_bubble_.reset(new SystemBubbleWrapper(notification_bubble));
566 notification_bubble_->InitView(this, anchor, &init_params, false);
567
568 if (notification_bubble->bubble_view()->child_count() == 0) {
569 // It is possible that none of the items generated actual notifications.
570 DestroyNotificationBubble();
571 return;
572 }
573 if (hide_notifications_)
574 notification_bubble->SetVisible(false);
575 else
576 UpdateWebNotifications();
577 }
578
579 void SystemTray::UpdateWebNotifications() {
580 TrayBubbleView* bubble_view = NULL;
581 if (notification_bubble_)
582 bubble_view = notification_bubble_->bubble_view();
583 else if (system_bubble_)
584 bubble_view = system_bubble_->bubble_view();
585
586 int height = 0;
587 if (bubble_view) {
588 gfx::Rect work_area =
589 display::Screen::GetScreen()
590 ->GetDisplayNearestWindow(bubble_view->GetWidget()->GetNativeView())
591 .work_area();
592 height =
593 std::max(0, work_area.height() - bubble_view->GetBoundsInScreen().y());
594 }
595 if (web_notification_tray_)
596 web_notification_tray_->SetTrayBubbleHeight(height);
597 }
598
599 base::string16 SystemTray::GetAccessibleTimeString(
600 const base::Time& now) const {
601 base::HourClockType hour_type =
602 WmShell::Get()->system_tray_delegate()->GetHourClockType();
603 return base::TimeFormatTimeOfDayWithHourClockType(now, hour_type,
604 base::kKeepAmPm);
605 }
606
607 void SystemTray::SetShelfAlignment(ShelfAlignment alignment) {
608 if (alignment == shelf_alignment())
609 return;
610 TrayBackgroundView::SetShelfAlignment(alignment);
611 UpdateAfterShelfAlignmentChange(alignment);
612 // Destroy any existing bubble so that it is rebuilt correctly.
613 CloseSystemBubbleAndDeactivateSystemTray();
614 // Rebuild any notification bubble.
615 if (notification_bubble_) {
616 notification_bubble_.reset();
617 UpdateNotificationBubble();
618 // UpdateWebNotifications() should be called in UpdateNotificationBubble().
619 } else if (!hide_notifications_) {
620 UpdateWebNotifications();
621 }
622 }
623
624 void SystemTray::AnchorUpdated() {
625 if (notification_bubble_) {
626 notification_bubble_->bubble_view()->UpdateBubble();
627 // Ensure that the notification buble is above the shelf/status area.
628 notification_bubble_->bubble_view()->GetWidget()->StackAtTop();
629 UpdateBubbleViewArrow(notification_bubble_->bubble_view());
630 }
631 if (system_bubble_) {
632 system_bubble_->bubble_view()->UpdateBubble();
633 UpdateBubbleViewArrow(system_bubble_->bubble_view());
634 }
635 }
636
637 void SystemTray::BubbleResized(const TrayBubbleView* bubble_view) {
638 UpdateWebNotifications();
639 }
640
641 void SystemTray::HideBubbleWithView(const TrayBubbleView* bubble_view) {
642 if (system_bubble_.get() && bubble_view == system_bubble_->bubble_view()) {
643 DestroySystemBubble();
644 UpdateNotificationBubble(); // State changed, re-create notifications.
645 shelf()->UpdateAutoHideState();
646 } else if (notification_bubble_.get() &&
647 bubble_view == notification_bubble_->bubble_view()) {
648 DestroyNotificationBubble();
649 }
650 }
651
652 void SystemTray::ClickedOutsideBubble() {
653 if (!system_bubble_ || system_bubble_->is_persistent())
654 return;
655 HideBubbleWithView(system_bubble_->bubble_view());
656 }
657
658 void SystemTray::BubbleViewDestroyed() {
659 if (system_bubble_) {
660 system_bubble_->bubble()->DestroyItemViews();
661 system_bubble_->bubble()->BubbleViewDestroyed();
662 }
663 }
664
665 void SystemTray::OnMouseEnteredView() {
666 if (system_bubble_)
667 system_bubble_->bubble()->StopAutoCloseTimer();
668 }
669
670 void SystemTray::OnMouseExitedView() {
671 if (system_bubble_)
672 system_bubble_->bubble()->RestartAutoCloseTimer();
673 }
674
675 base::string16 SystemTray::GetAccessibleNameForBubble() {
676 return GetAccessibleNameForTray();
677 }
678
679 gfx::Rect SystemTray::GetAnchorRect(
680 views::Widget* anchor_widget,
681 TrayBubbleView::AnchorType anchor_type,
682 TrayBubbleView::AnchorAlignment anchor_alignment) const {
683 return GetBubbleAnchorRect(anchor_widget, anchor_type, anchor_alignment);
684 }
685
686 void SystemTray::OnBeforeBubbleWidgetInit(
687 views::Widget* anchor_widget,
688 views::Widget* bubble_widget,
689 views::Widget::InitParams* params) const {
690 // Place the bubble in the same root window as |anchor_widget|.
691 WmLookup::Get()
692 ->GetWindowForWidget(anchor_widget)
693 ->GetRootWindowController()
694 ->ConfigureWidgetInitParamsForContainer(
695 bubble_widget, kShellWindowId_SettingBubbleContainer, params);
696 }
697
698 void SystemTray::HideBubble(const TrayBubbleView* bubble_view) {
699 HideBubbleWithView(bubble_view);
700 }
701
702 views::View* SystemTray::GetTrayItemViewForTest(SystemTrayItem* item) {
703 std::map<SystemTrayItem*, views::View*>::iterator it =
704 tray_item_map_.find(item);
705 return it == tray_item_map_.end() ? NULL : it->second;
706 }
707
708 TrayCast* SystemTray::GetTrayCastForTesting() const {
709 return tray_cast_;
710 }
711
712 TrayDate* SystemTray::GetTrayDateForTesting() const {
713 return tray_date_;
714 }
715
716 TrayUpdate* SystemTray::GetTrayUpdateForTesting() const {
717 return tray_update_;
718 }
719
720 bool SystemTray::PerformAction(const ui::Event& event) {
721 // If we're already showing the default view, hide it; otherwise, show it
722 // (and hide any popup that's currently shown).
723 if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) {
724 system_bubble_->bubble()->Close();
725 } else {
726 int arrow_offset = TrayBubbleView::InitParams::kArrowDefaultOffset;
727 if (event.IsMouseEvent() || event.type() == ui::ET_GESTURE_TAP) {
728 const ui::LocatedEvent& located_event =
729 static_cast<const ui::LocatedEvent&>(event);
730 if (IsHorizontalAlignment(shelf_alignment())) {
731 gfx::Point point(located_event.x(), 0);
732 ConvertPointToWidget(this, &point);
733 arrow_offset = point.x();
734 }
735 }
736 ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset, false);
737 }
738 return true;
739 }
740
741 void SystemTray::CloseSystemBubbleAndDeactivateSystemTray() {
742 system_bubble_.reset();
743 // When closing a system bubble with the alternate shelf layout, we need to
744 // turn off the active tinting of the shelf.
745 if (full_system_tray_menu_) {
746 SetDrawBackgroundAsActive(false);
747 full_system_tray_menu_ = false;
748 }
749 }
750
751 void SystemTray::RecordSystemMenuMetrics() {
752 DCHECK(system_bubble_);
753
754 TrayBubbleView* bubble_view = system_bubble_->bubble_view();
755 int num_rows = 0;
756 for (int i = 0; i < bubble_view->child_count(); i++) {
757 // Certain menu rows are attached by default but can set themselves as
758 // invisible (IME is one such example). Count only user-visible rows.
759 if (bubble_view->child_at(i)->visible())
760 num_rows++;
761 }
762 UMA_HISTOGRAM_COUNTS_100("Ash.SystemMenu.Rows", num_rows);
763
764 int work_area_height =
765 display::Screen::GetScreen()
766 ->GetDisplayNearestWindow(bubble_view->GetWidget()->GetNativeView())
767 .work_area()
768 .height();
769 if (work_area_height > 0) {
770 UMA_HISTOGRAM_CUSTOM_COUNTS(
771 "Ash.SystemMenu.PercentageOfWorkAreaHeightCoveredByMenu",
772 100 * bubble_view->height() / work_area_height, 1, 300, 100);
773 }
774 }
775
776 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/tray/system_tray.h ('k') | ash/system/tray/system_tray_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698