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

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

Issue 2734653002: chromeos: Move files in //ash/common to //ash (Closed)
Patch Set: fix a11y tests, fix docs Created 3 years, 9 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/common/system/tray/system_tray.h ('k') | ash/common/system/tray/system_tray_bubble.h » ('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/common/system/tray/system_tray.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <vector>
10
11 #include "ash/common/key_event_watcher.h"
12 #include "ash/common/login_status.h"
13 #include "ash/common/material_design/material_design_controller.h"
14 #include "ash/common/session/session_state_delegate.h"
15 #include "ash/common/shelf/wm_shelf.h"
16 #include "ash/common/shelf/wm_shelf_util.h"
17 #include "ash/common/system/chromeos/audio/tray_audio.h"
18 #include "ash/common/system/chromeos/bluetooth/tray_bluetooth.h"
19 #include "ash/common/system/chromeos/brightness/tray_brightness.h"
20 #include "ash/common/system/chromeos/cast/tray_cast.h"
21 #include "ash/common/system/chromeos/enterprise/tray_enterprise.h"
22 #include "ash/common/system/chromeos/media_security/multi_profile_media_tray_ite m.h"
23 #include "ash/common/system/chromeos/network/tray_network.h"
24 #include "ash/common/system/chromeos/network/tray_vpn.h"
25 #include "ash/common/system/chromeos/power/power_status.h"
26 #include "ash/common/system/chromeos/power/tray_power.h"
27 #include "ash/common/system/chromeos/screen_security/screen_capture_tray_item.h"
28 #include "ash/common/system/chromeos/screen_security/screen_share_tray_item.h"
29 #include "ash/common/system/chromeos/session/tray_session_length_limit.h"
30 #include "ash/common/system/chromeos/settings/tray_settings.h"
31 #include "ash/common/system/chromeos/supervised/tray_supervised_user.h"
32 #include "ash/common/system/chromeos/tray_caps_lock.h"
33 #include "ash/common/system/chromeos/tray_tracing.h"
34 #include "ash/common/system/date/tray_date.h"
35 #include "ash/common/system/date/tray_system_info.h"
36 #include "ash/common/system/ime/tray_ime_chromeos.h"
37 #include "ash/common/system/tiles/tray_tiles.h"
38 #include "ash/common/system/tray/system_tray_controller.h"
39 #include "ash/common/system/tray/system_tray_delegate.h"
40 #include "ash/common/system/tray/system_tray_item.h"
41 #include "ash/common/system/tray/tray_bubble_wrapper.h"
42 #include "ash/common/system/tray/tray_constants.h"
43 #include "ash/common/system/tray_accessibility.h"
44 #include "ash/common/system/update/tray_update.h"
45 #include "ash/common/system/user/tray_user.h"
46 #include "ash/common/system/web_notification/web_notification_tray.h"
47 #include "ash/common/wm/container_finder.h"
48 #include "ash/common/wm_activation_observer.h"
49 #include "ash/common/wm_shell.h"
50 #include "ash/common/wm_window.h"
51 #include "ash/public/cpp/shell_window_ids.h"
52 #include "ash/root_window_controller.h"
53 #include "ash/strings/grit/ash_strings.h"
54 #include "base/logging.h"
55 #include "base/memory/ptr_util.h"
56 #include "base/metrics/histogram_macros.h"
57 #include "base/timer/timer.h"
58 #include "ui/base/accelerators/accelerator.h"
59 #include "ui/base/l10n/l10n_util.h"
60 #include "ui/compositor/layer.h"
61 #include "ui/display/display.h"
62 #include "ui/display/screen.h"
63 #include "ui/events/event_constants.h"
64 #include "ui/gfx/canvas.h"
65 #include "ui/gfx/skia_util.h"
66 #include "ui/message_center/message_center.h"
67 #include "ui/message_center/message_center_style.h"
68 #include "ui/views/border.h"
69 #include "ui/views/controls/label.h"
70 #include "ui/views/view.h"
71 #include "ui/views/widget/widget.h"
72
73 using views::TrayBubbleView;
74
75 namespace ash {
76
77 namespace {
78
79 // A tray item that just reserves space in the tray.
80 class PaddingTrayItem : public SystemTrayItem {
81 public:
82 PaddingTrayItem() : SystemTrayItem(nullptr, UMA_NOT_RECORDED) {}
83 ~PaddingTrayItem() override {}
84
85 // SystemTrayItem:
86 views::View* CreateTrayView(LoginStatus status) override {
87 return new PaddingView();
88 }
89
90 private:
91 class PaddingView : public views::View {
92 public:
93 PaddingView() {}
94 ~PaddingView() override {}
95
96 private:
97 gfx::Size GetPreferredSize() const override {
98 // The other tray items already have some padding baked in so we have to
99 // subtract that off.
100 const int side = kTrayEdgePadding - kTrayImageItemPadding;
101 return gfx::Size(side, side);
102 }
103
104 DISALLOW_COPY_AND_ASSIGN(PaddingView);
105 };
106
107 DISALLOW_COPY_AND_ASSIGN(PaddingTrayItem);
108 };
109
110 } // namespace
111
112 // Class to initialize and manage the SystemTrayBubble and TrayBubbleWrapper
113 // instances for a bubble.
114
115 class SystemBubbleWrapper {
116 public:
117 // Takes ownership of |bubble|.
118 explicit SystemBubbleWrapper(SystemTrayBubble* bubble)
119 : bubble_(bubble), is_persistent_(false) {}
120
121 // Initializes the bubble view and creates |bubble_wrapper_|.
122 void InitView(TrayBackgroundView* tray,
123 views::View* anchor,
124 const gfx::Insets& anchor_insets,
125 TrayBubbleView::InitParams* init_params,
126 bool is_persistent) {
127 DCHECK(anchor);
128 LoginStatus login_status =
129 WmShell::Get()->system_tray_delegate()->GetUserLoginStatus();
130 bubble_->InitView(anchor, login_status, init_params);
131 bubble_->bubble_view()->set_anchor_view_insets(anchor_insets);
132 bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_->bubble_view()));
133 is_persistent_ = is_persistent;
134
135 // If ChromeVox is enabled, focus the default item if no item is focused and
136 // there isn't a delayed close.
137 if (WmShell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled() &&
138 !is_persistent) {
139 bubble_->FocusDefaultIfNeeded();
140 }
141 }
142
143 // Convenience accessors:
144 SystemTrayBubble* bubble() const { return bubble_.get(); }
145 SystemTrayBubble::BubbleType bubble_type() const {
146 return bubble_->bubble_type();
147 }
148 TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); }
149 bool is_persistent() const { return is_persistent_; }
150
151 private:
152 std::unique_ptr<SystemTrayBubble> bubble_;
153 std::unique_ptr<TrayBubbleWrapper> bubble_wrapper_;
154 bool is_persistent_;
155
156 DISALLOW_COPY_AND_ASSIGN(SystemBubbleWrapper);
157 };
158
159 // An activation observer to close the bubble if the window other
160 // than system bubble nor popup notification is activated.
161 class SystemTray::ActivationObserver : public WmActivationObserver {
162 public:
163 explicit ActivationObserver(SystemTray* tray) : tray_(tray) {
164 DCHECK(tray_);
165 WmShell::Get()->AddActivationObserver(this);
166 }
167
168 ~ActivationObserver() override {
169 WmShell::Get()->RemoveActivationObserver(this);
170 }
171
172 // WmActivationObserver:
173 void OnWindowActivated(WmWindow* gained_active,
174 WmWindow* lost_active) override {
175 if (!tray_->HasSystemBubble() || !gained_active)
176 return;
177
178 int container_id =
179 wm::GetContainerForWindow(gained_active)->GetShellWindowId();
180
181 // Don't close the bubble if a popup notification is activated.
182 if (container_id == kShellWindowId_StatusContainer)
183 return;
184
185 if (tray_->GetSystemBubble()->bubble_view()->GetWidget() !=
186 gained_active->GetInternalWidget()) {
187 tray_->CloseSystemBubble();
188 }
189 }
190 void OnAttemptToReactivateWindow(WmWindow* request_active,
191 WmWindow* actual_active) override {}
192
193 private:
194 SystemTray* tray_;
195
196 DISALLOW_COPY_AND_ASSIGN(ActivationObserver);
197 };
198
199 // SystemTray
200
201 SystemTray::SystemTray(WmShelf* wm_shelf)
202 : TrayBackgroundView(wm_shelf),
203 web_notification_tray_(nullptr),
204 detailed_item_(nullptr),
205 default_bubble_height_(0),
206 full_system_tray_menu_(false),
207 tray_accessibility_(nullptr),
208 tray_audio_(nullptr),
209 tray_cast_(nullptr),
210 tray_date_(nullptr),
211 tray_network_(nullptr),
212 tray_tiles_(nullptr),
213 tray_system_info_(nullptr),
214 tray_update_(nullptr),
215 screen_capture_tray_item_(nullptr),
216 screen_share_tray_item_(nullptr) {
217 if (MaterialDesignController::IsShelfMaterial()) {
218 SetInkDropMode(InkDropMode::ON);
219 SetContentsBackground(false);
220
221 // Since user avatar is on the right hand side of System tray of a
222 // horizontal shelf and that is sufficient to indicate separation, no
223 // separator is required.
224 set_separator_visibility(false);
225 } else {
226 SetContentsBackground(true);
227 }
228 }
229
230 SystemTray::~SystemTray() {
231 // Destroy any child views that might have back pointers before ~View().
232 activation_observer_.reset();
233 key_event_watcher_.reset();
234 system_bubble_.reset();
235 for (const auto& item : items_)
236 item->DestroyTrayView();
237 }
238
239 void SystemTray::InitializeTrayItems(
240 SystemTrayDelegate* delegate,
241 WebNotificationTray* web_notification_tray) {
242 DCHECK(web_notification_tray);
243 web_notification_tray_ = web_notification_tray;
244 TrayBackgroundView::Initialize();
245 CreateItems(delegate);
246 }
247
248 void SystemTray::Shutdown() {
249 DCHECK(web_notification_tray_);
250 web_notification_tray_ = nullptr;
251 }
252
253 void SystemTray::CreateItems(SystemTrayDelegate* delegate) {
254 const bool use_md = MaterialDesignController::IsSystemTrayMenuMaterial();
255
256 // Create user items for each possible user.
257 int maximum_user_profiles = WmShell::Get()
258 ->GetSessionStateDelegate()
259 ->GetMaximumNumberOfLoggedInUsers();
260 for (int i = 0; i < maximum_user_profiles; i++)
261 AddTrayItem(base::MakeUnique<TrayUser>(this, i));
262
263 // Crucially, this trailing padding has to be inside the user item(s).
264 // Otherwise it could be a main axis margin on the tray's box layout.
265 AddTrayItem(base::MakeUnique<PaddingTrayItem>());
266
267 tray_accessibility_ = new TrayAccessibility(this);
268 if (!use_md)
269 tray_date_ = new TrayDate(this);
270 tray_update_ = new TrayUpdate(this);
271
272 AddTrayItem(base::MakeUnique<TraySessionLengthLimit>(this));
273 AddTrayItem(base::MakeUnique<TrayEnterprise>(this));
274 AddTrayItem(base::MakeUnique<TraySupervisedUser>(this));
275 AddTrayItem(base::MakeUnique<TrayIME>(this));
276 AddTrayItem(base::WrapUnique(tray_accessibility_));
277 AddTrayItem(base::MakeUnique<TrayTracing>(this));
278 AddTrayItem(
279 base::MakeUnique<TrayPower>(this, message_center::MessageCenter::Get()));
280 tray_network_ = new TrayNetwork(this);
281 AddTrayItem(base::WrapUnique(tray_network_));
282 AddTrayItem(base::MakeUnique<TrayVPN>(this));
283 AddTrayItem(base::MakeUnique<TrayBluetooth>(this));
284 tray_cast_ = new TrayCast(this);
285 AddTrayItem(base::WrapUnique(tray_cast_));
286 screen_capture_tray_item_ = new ScreenCaptureTrayItem(this);
287 AddTrayItem(base::WrapUnique(screen_capture_tray_item_));
288 screen_share_tray_item_ = new ScreenShareTrayItem(this);
289 AddTrayItem(base::WrapUnique(screen_share_tray_item_));
290 AddTrayItem(base::MakeUnique<MultiProfileMediaTrayItem>(this));
291 tray_audio_ = new TrayAudio(this);
292 AddTrayItem(base::WrapUnique(tray_audio_));
293 AddTrayItem(base::MakeUnique<TrayBrightness>(this));
294 AddTrayItem(base::MakeUnique<TrayCapsLock>(this));
295 // TODO(jamescook): Remove this when mus has support for display management
296 // and we have a DisplayManager equivalent. See http://crbug.com/548429
297 std::unique_ptr<SystemTrayItem> tray_rotation_lock =
298 delegate->CreateRotationLockTrayItem(this);
299 if (tray_rotation_lock)
300 AddTrayItem(std::move(tray_rotation_lock));
301 if (!use_md)
302 AddTrayItem(base::MakeUnique<TraySettings>(this));
303 AddTrayItem(base::WrapUnique(tray_update_));
304 if (use_md) {
305 tray_tiles_ = new TrayTiles(this);
306 AddTrayItem(base::WrapUnique(tray_tiles_));
307 tray_system_info_ = new TraySystemInfo(this);
308 AddTrayItem(base::WrapUnique(tray_system_info_));
309 // Leading padding.
310 AddTrayItem(base::MakeUnique<PaddingTrayItem>());
311 } else {
312 AddTrayItem(base::WrapUnique(tray_date_));
313 }
314 }
315
316 void SystemTray::AddTrayItem(std::unique_ptr<SystemTrayItem> item) {
317 SystemTrayItem* item_ptr = item.get();
318 items_.push_back(std::move(item));
319
320 SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate();
321 views::View* tray_item =
322 item_ptr->CreateTrayView(delegate->GetUserLoginStatus());
323 item_ptr->UpdateAfterShelfAlignmentChange(shelf_alignment());
324
325 if (tray_item) {
326 tray_container()->AddChildViewAt(tray_item, 0);
327 PreferredSizeChanged();
328 tray_item_map_[item_ptr] = tray_item;
329 }
330 }
331
332 std::vector<SystemTrayItem*> SystemTray::GetTrayItems() const {
333 std::vector<SystemTrayItem*> result;
334 for (const auto& item : items_)
335 result.push_back(item.get());
336 return result;
337 }
338
339 void SystemTray::ShowDefaultView(BubbleCreationType creation_type) {
340 if (creation_type != BUBBLE_USE_EXISTING)
341 WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_MENU_OPENED);
342 ShowItems(GetTrayItems(), false, true, creation_type, false);
343 }
344
345 void SystemTray::ShowPersistentDefaultView() {
346 ShowItems(GetTrayItems(), false, false, BUBBLE_CREATE_NEW, true);
347 }
348
349 void SystemTray::ShowDetailedView(SystemTrayItem* item,
350 int close_delay,
351 bool activate,
352 BubbleCreationType creation_type) {
353 std::vector<SystemTrayItem*> items;
354 // The detailed view with timeout means a UI to show the current system state,
355 // like the audio level or brightness. Such UI should behave as persistent and
356 // keep its own logic for the appearance.
357 bool persistent =
358 (!activate && close_delay > 0 && creation_type == BUBBLE_CREATE_NEW);
359 items.push_back(item);
360 ShowItems(items, true, activate, creation_type, persistent);
361 if (system_bubble_)
362 system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
363 }
364
365 void SystemTray::SetDetailedViewCloseDelay(int close_delay) {
366 if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DETAILED))
367 system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
368 }
369
370 void SystemTray::HideDetailedView(SystemTrayItem* item, bool animate) {
371 if (item != detailed_item_)
372 return;
373
374 if (!animate) {
375 // In unittest, GetSystemBubble might return nullptr.
376 if (GetSystemBubble()) {
377 GetSystemBubble()
378 ->bubble_view()
379 ->GetWidget()
380 ->SetVisibilityAnimationTransition(
381 views::Widget::VisibilityTransition::ANIMATE_NONE);
382 }
383 }
384
385 DestroySystemBubble();
386 }
387
388 void SystemTray::UpdateAfterLoginStatusChange(LoginStatus login_status) {
389 DestroySystemBubble();
390
391 for (const auto& item : items_)
392 item->UpdateAfterLoginStatusChange(login_status);
393
394 // Items default to SHELF_ALIGNMENT_BOTTOM. Update them if the initial
395 // position of the shelf differs.
396 if (!IsHorizontalAlignment(shelf_alignment()))
397 UpdateAfterShelfAlignmentChange(shelf_alignment());
398
399 SetVisible(true);
400 PreferredSizeChanged();
401 }
402
403 void SystemTray::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
404 for (const auto& item : items_)
405 item->UpdateAfterShelfAlignmentChange(alignment);
406 }
407
408 bool SystemTray::ShouldShowShelf() const {
409 return system_bubble_.get() && system_bubble_->bubble()->ShouldShowShelf();
410 }
411
412 bool SystemTray::HasSystemBubble() const {
413 return system_bubble_.get() != NULL;
414 }
415
416 SystemTrayBubble* SystemTray::GetSystemBubble() {
417 if (!system_bubble_)
418 return NULL;
419 return system_bubble_->bubble();
420 }
421
422 bool SystemTray::IsSystemBubbleVisible() const {
423 return HasSystemBubble() && system_bubble_->bubble()->IsVisible();
424 }
425
426 bool SystemTray::CloseSystemBubble() const {
427 if (!system_bubble_)
428 return false;
429 CHECK(!activating_);
430 system_bubble_->bubble()->Close();
431 return true;
432 }
433
434 views::View* SystemTray::GetHelpButtonView() const {
435 if (MaterialDesignController::IsSystemTrayMenuMaterial())
436 return tray_tiles_->GetHelpButtonView();
437 return tray_date_->GetHelpButtonView();
438 }
439
440 TrayAudio* SystemTray::GetTrayAudio() const {
441 return tray_audio_;
442 }
443
444 // Private methods.
445
446 bool SystemTray::HasSystemBubbleType(SystemTrayBubble::BubbleType type) {
447 return system_bubble_.get() && system_bubble_->bubble_type() == type;
448 }
449
450 void SystemTray::DestroySystemBubble() {
451 CloseSystemBubbleAndDeactivateSystemTray();
452 detailed_item_ = NULL;
453 UpdateWebNotifications();
454 }
455
456 base::string16 SystemTray::GetAccessibleNameForTray() {
457 base::string16 time = GetAccessibleTimeString(base::Time::Now());
458 base::string16 battery = PowerStatus::Get()->GetAccessibleNameString(false);
459 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBLE_DESCRIPTION,
460 time, battery);
461 }
462
463 void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items,
464 bool detailed,
465 bool can_activate,
466 BubbleCreationType creation_type,
467 bool persistent) {
468 // No system tray bubbles in kiosk mode.
469 SystemTrayDelegate* system_tray_delegate =
470 WmShell::Get()->system_tray_delegate();
471 if (system_tray_delegate->GetUserLoginStatus() == LoginStatus::KIOSK_APP ||
472 system_tray_delegate->GetUserLoginStatus() ==
473 LoginStatus::ARC_KIOSK_APP) {
474 return;
475 }
476
477 // Destroy any existing bubble and create a new one.
478 SystemTrayBubble::BubbleType bubble_type =
479 detailed ? SystemTrayBubble::BUBBLE_TYPE_DETAILED
480 : SystemTrayBubble::BUBBLE_TYPE_DEFAULT;
481
482 if (system_bubble_.get() && creation_type == BUBBLE_USE_EXISTING) {
483 system_bubble_->bubble()->UpdateView(items, bubble_type);
484 // If ChromeVox is enabled, focus the default item if no item is focused.
485 if (WmShell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled())
486 system_bubble_->bubble()->FocusDefaultIfNeeded();
487 } else {
488 // Cleanup the existing bubble before showing a new one. Otherwise, it's
489 // possible to confuse the new system bubble with the old one during
490 // destruction, leading to subtle errors/crashes such as crbug.com/545166.
491 DestroySystemBubble();
492
493 // Remember if the menu is a single property (like e.g. volume) or the
494 // full tray menu. Note that in case of the |BUBBLE_USE_EXISTING| case
495 // above, |full_system_tray_menu_| does not get changed since the fact that
496 // the menu is full (or not) doesn't change even if a "single property"
497 // (like network) replaces most of the menu.
498 full_system_tray_menu_ = items.size() > 1;
499
500 // The menu width is fixed for all languages in material design.
501 int menu_width = kTrayMenuMinimumWidthMd;
502 if (!MaterialDesignController::IsSystemTrayMenuMaterial()) {
503 // The menu width is fixed, and it is a per language setting.
504 menu_width = std::max(
505 kTrayMenuMinimumWidth,
506 WmShell::Get()->system_tray_delegate()->GetSystemTrayMenuWidth());
507 }
508
509 TrayBubbleView::InitParams init_params(GetAnchorAlignment(), menu_width,
510 kTrayPopupMaxWidth);
511 // TODO(oshima): Change TrayBubbleView itself.
512 init_params.can_activate = false;
513 if (detailed) {
514 // This is the case where a volume control or brightness control bubble
515 // is created.
516 init_params.max_height = default_bubble_height_;
517 init_params.bg_color = kBackgroundColor;
518 } else {
519 init_params.bg_color = kHeaderBackgroundColor;
520 }
521 if (bubble_type == SystemTrayBubble::BUBBLE_TYPE_DEFAULT)
522 init_params.close_on_deactivate = !persistent;
523 SystemTrayBubble* bubble = new SystemTrayBubble(this, items, bubble_type);
524
525 system_bubble_.reset(new SystemBubbleWrapper(bubble));
526 system_bubble_->InitView(this, GetBubbleAnchor(), GetBubbleAnchorInsets(),
527 &init_params, persistent);
528
529 activation_observer_.reset(persistent ? nullptr
530 : new ActivationObserver(this));
531
532 // Record metrics for the system menu when the default view is invoked.
533 if (!detailed)
534 RecordSystemMenuMetrics();
535 }
536 // Save height of default view for creating detailed views directly.
537 if (!detailed)
538 default_bubble_height_ = system_bubble_->bubble_view()->height();
539
540 key_event_watcher_.reset();
541 if (can_activate)
542 CreateKeyEventWatcher();
543
544 if (detailed && items.size() > 0)
545 detailed_item_ = items[0];
546 else
547 detailed_item_ = NULL;
548
549 UpdateWebNotifications();
550 shelf()->UpdateAutoHideState();
551
552 // When we show the system menu in our alternate shelf layout, we need to
553 // tint the background.
554 if (full_system_tray_menu_)
555 SetIsActive(true);
556 }
557
558 void SystemTray::UpdateWebNotifications() {
559 TrayBubbleView* bubble_view = NULL;
560 if (system_bubble_)
561 bubble_view = system_bubble_->bubble_view();
562
563 int height = 0;
564 if (bubble_view) {
565 gfx::Rect work_area =
566 display::Screen::GetScreen()
567 ->GetDisplayNearestWindow(bubble_view->GetWidget()->GetNativeView())
568 .work_area();
569 height =
570 std::max(0, work_area.bottom() - bubble_view->GetBoundsInScreen().y());
571 }
572 if (web_notification_tray_)
573 web_notification_tray_->SetTrayBubbleHeight(height);
574 }
575
576 base::string16 SystemTray::GetAccessibleTimeString(
577 const base::Time& now) const {
578 base::HourClockType hour_type =
579 WmShell::Get()->system_tray_controller()->hour_clock_type();
580 return base::TimeFormatTimeOfDayWithHourClockType(now, hour_type,
581 base::kKeepAmPm);
582 }
583
584 void SystemTray::SetShelfAlignment(ShelfAlignment alignment) {
585 if (alignment == shelf_alignment())
586 return;
587 TrayBackgroundView::SetShelfAlignment(alignment);
588 UpdateAfterShelfAlignmentChange(alignment);
589 // Destroy any existing bubble so that it is rebuilt correctly.
590 CloseSystemBubbleAndDeactivateSystemTray();
591 // Rebuild any notification bubble.
592 UpdateWebNotifications();
593 }
594
595 void SystemTray::AnchorUpdated() {
596 if (system_bubble_) {
597 system_bubble_->bubble_view()->UpdateBubble();
598 UpdateBubbleViewArrow(system_bubble_->bubble_view());
599 }
600 }
601
602 void SystemTray::BubbleResized(const TrayBubbleView* bubble_view) {
603 UpdateWebNotifications();
604 }
605
606 void SystemTray::HideBubbleWithView(const TrayBubbleView* bubble_view) {
607 if (system_bubble_.get() && bubble_view == system_bubble_->bubble_view()) {
608 DestroySystemBubble();
609 shelf()->UpdateAutoHideState();
610 }
611 }
612
613 void SystemTray::ClickedOutsideBubble() {
614 if (!system_bubble_ || system_bubble_->is_persistent())
615 return;
616 HideBubbleWithView(system_bubble_->bubble_view());
617 }
618
619 void SystemTray::BubbleViewDestroyed() {
620 if (system_bubble_) {
621 system_bubble_->bubble()->DestroyItemViews();
622 system_bubble_->bubble()->BubbleViewDestroyed();
623 }
624 }
625
626 void SystemTray::OnMouseEnteredView() {
627 if (system_bubble_)
628 system_bubble_->bubble()->StopAutoCloseTimer();
629 }
630
631 void SystemTray::OnMouseExitedView() {
632 if (system_bubble_)
633 system_bubble_->bubble()->RestartAutoCloseTimer();
634 }
635
636 base::string16 SystemTray::GetAccessibleNameForBubble() {
637 return GetAccessibleNameForTray();
638 }
639
640 void SystemTray::OnBeforeBubbleWidgetInit(
641 views::Widget* anchor_widget,
642 views::Widget* bubble_widget,
643 views::Widget::InitParams* params) const {
644 // Place the bubble in the same root window as |anchor_widget|.
645 WmWindow::Get(anchor_widget->GetNativeWindow())
646 ->GetRootWindowController()
647 ->ConfigureWidgetInitParamsForContainer(
648 bubble_widget, kShellWindowId_SettingBubbleContainer, params);
649 }
650
651 void SystemTray::HideBubble(const TrayBubbleView* bubble_view) {
652 HideBubbleWithView(bubble_view);
653 }
654
655 views::View* SystemTray::GetTrayItemViewForTest(SystemTrayItem* item) {
656 std::map<SystemTrayItem*, views::View*>::iterator it =
657 tray_item_map_.find(item);
658 return it == tray_item_map_.end() ? NULL : it->second;
659 }
660
661 TrayCast* SystemTray::GetTrayCastForTesting() const {
662 return tray_cast_;
663 }
664
665 TrayDate* SystemTray::GetTrayDateForTesting() const {
666 return tray_date_;
667 }
668
669 TrayNetwork* SystemTray::GetTrayNetworkForTesting() const {
670 return tray_network_;
671 }
672
673 TraySystemInfo* SystemTray::GetTraySystemInfoForTesting() const {
674 return tray_system_info_;
675 }
676
677 TrayTiles* SystemTray::GetTrayTilesForTesting() const {
678 return tray_tiles_;
679 }
680
681 void SystemTray::CloseBubble(const ui::KeyEvent& key_event) {
682 CloseSystemBubble();
683 }
684
685 void SystemTray::ActivateAndStartNavigation(const ui::KeyEvent& key_event) {
686 if (!system_bubble_)
687 return;
688 activating_ = true;
689 ActivateBubble();
690 activating_ = false;
691 // TODO(oshima): This is to troubleshoot the issue crbug.com/651242. Remove
692 // once the root cause is fixed.
693 CHECK(system_bubble_) << " the bubble was deleted while activaing it";
694
695 views::Widget* widget = GetSystemBubble()->bubble_view()->GetWidget();
696 widget->GetFocusManager()->OnKeyEvent(key_event);
697 }
698
699 void SystemTray::CreateKeyEventWatcher() {
700 key_event_watcher_ = WmShell::Get()->CreateKeyEventWatcher();
701 // mustash does not yet support KeyEventWatcher. http://crbug.com/649600.
702 if (!key_event_watcher_)
703 return;
704 key_event_watcher_->AddKeyEventCallback(
705 ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE),
706 base::Bind(&SystemTray::CloseBubble, base::Unretained(this)));
707 key_event_watcher_->AddKeyEventCallback(
708 ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE),
709 base::Bind(&SystemTray::ActivateAndStartNavigation,
710 base::Unretained(this)));
711 key_event_watcher_->AddKeyEventCallback(
712 ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN),
713 base::Bind(&SystemTray::ActivateAndStartNavigation,
714 base::Unretained(this)));
715 }
716
717 void SystemTray::ActivateBubble() {
718 TrayBubbleView* bubble_view = GetSystemBubble()->bubble_view();
719 bubble_view->set_can_activate(true);
720 bubble_view->GetWidget()->Activate();
721 }
722
723 bool SystemTray::PerformAction(const ui::Event& event) {
724 // If we're already showing the default view, hide it; otherwise, show it
725 // (and hide any popup that's currently shown).
726 if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) {
727 system_bubble_->bubble()->Close();
728 } else {
729 ShowDefaultView(BUBBLE_CREATE_NEW);
730 if (event.IsKeyEvent() || (event.flags() & ui::EF_TOUCH_ACCESSIBILITY))
731 ActivateBubble();
732 }
733 return true;
734 }
735
736 void SystemTray::CloseSystemBubbleAndDeactivateSystemTray() {
737 CHECK(!activating_);
738 activation_observer_.reset();
739 key_event_watcher_.reset();
740 system_bubble_.reset();
741 // When closing a system bubble with the alternate shelf layout, we need to
742 // turn off the active tinting of the shelf.
743 if (full_system_tray_menu_) {
744 SetIsActive(false);
745 full_system_tray_menu_ = false;
746 }
747 }
748
749 void SystemTray::RecordSystemMenuMetrics() {
750 DCHECK(system_bubble_);
751
752 system_bubble_->bubble()->RecordVisibleRowMetrics();
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/common/system/tray/system_tray.h ('k') | ash/common/system/tray/system_tray_bubble.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698