15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/ash_switches.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/metrics/user_metrics_recorder.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shelf/shelf_layout_manager.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell_window_ids.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/audio/tray_audio.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/bluetooth/tray_bluetooth.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/date/tray_date.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/ime/tray_ime.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/status_area_widget.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray_delegate.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray_item.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/tray_bubble_wrapper.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/tray_constants.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray_accessibility.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray_update.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/user/login_status.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/user/tray_user.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/system/user/tray_user_separator.h"
26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ash/system/web_notification/web_notification_tray.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ash_strings.h"
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h"
34d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event_constants.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skia_util.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/border.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/label.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/box_layout.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/fill_layout.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS)
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/chromeos/audio/tray_audio_chromeos.h"
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/system/chromeos/brightness/tray_brightness.h"
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/system/chromeos/enterprise/tray_enterprise.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/chromeos/network/tray_network.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/chromeos/network/tray_sms.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/chromeos/network/tray_vpn.h"
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ash/system/chromeos/power/power_status.h"
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ash/system/chromeos/power/tray_power.h"
53a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "ash/system/chromeos/rotation/tray_rotation_lock.h"
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/system/chromeos/screen_security/screen_capture_tray_item.h"
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/system/chromeos/screen_security/screen_share_tray_item.h"
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/chromeos/session/tray_session_length_limit.h"
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ash/system/chromeos/settings/tray_settings.h"
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ash/system/chromeos/supervised/tray_supervised_user.h"
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/chromeos/tray_caps_lock.h"
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/system/chromeos/tray_display.h"
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/system/chromeos/tray_tracing.h"
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ash/system/tray/media_security/multi_profile_media_tray_item.h"
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/message_center/message_center.h"
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#elif defined(OS_WIN)
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/win/audio/tray_audio_win.h"
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "media/audio/win/core_audio_util_win.h"
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using views::TrayBubbleView;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The minimum width of the system tray menu width.
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMinimumSystemTrayMenuWidth = 300;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Class to initialize and manage the SystemTrayBubble and TrayBubbleWrapper
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// instances for a bubble.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SystemBubbleWrapper {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Takes ownership of |bubble|.
82c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  explicit SystemBubbleWrapper(SystemTrayBubble* bubble)
83c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      : bubble_(bubble), is_persistent_(false) {}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initializes the bubble view and creates |bubble_wrapper_|.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void InitView(TrayBackgroundView* tray,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                views::View* anchor,
881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                TrayBubbleView::InitParams* init_params,
891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                bool is_persistent) {
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(anchor);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    user::LoginStatus login_status =
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bubble_->InitView(anchor, login_status, init_params);
94c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_->bubble_view()));
95a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    // The system bubble should not have an arrow.
96a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    bubble_->bubble_view()->SetArrowPaintType(
97a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        views::BubbleBorder::PAINT_NONE);
981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    is_persistent_ = is_persistent;
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // If ChromeVox is enabled, focus the default item if no item is focused.
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (Shell::GetInstance()->accessibility_delegate()->
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        IsSpokenFeedbackEnabled()) {
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bubble_->FocusDefaultIfNeeded();
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convenience accessors:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SystemTrayBubble* bubble() const { return bubble_.get(); }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SystemTrayBubble::BubbleType bubble_type() const {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return bubble_->bubble_type();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); }
1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  bool is_persistent() const { return is_persistent_; }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
116c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<SystemTrayBubble> bubble_;
117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<TrayBubbleWrapper> bubble_wrapper_;
1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  bool is_persistent_;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SystemBubbleWrapper);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SystemTray
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
126c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSystemTray::SystemTray(StatusAreaWidget* status_area_widget)
127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    : TrayBackgroundView(status_area_widget),
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      items_(),
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_bubble_height_(0),
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      hide_notifications_(false),
131558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      full_system_tray_menu_(false),
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      tray_accessibility_(NULL),
1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      tray_date_(NULL) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetContentsBackground();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SystemTray::~SystemTray() {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Destroy any child views that might have back pointers before ~View().
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  system_bubble_.reset();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notification_bubble_.reset();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != items_.end();
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*it)->DestroyTrayView();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SystemTray::InitializeTrayItems(SystemTrayDelegate* delegate) {
149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  TrayBackgroundView::Initialize();
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CreateItems(delegate);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SystemTray::CreateItems(SystemTrayDelegate* delegate) {
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if !defined(OS_WIN)
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Create user items for each possible user.
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ash::Shell* shell = ash::Shell::GetInstance();
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int maximum_user_profiles =
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers();
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = 0; i < maximum_user_profiles; i++)
160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    AddTrayItem(new TrayUser(this, i));
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (maximum_user_profiles > 1) {
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Add a special double line separator between users and the rest of the
164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // menu if more then one user is logged in.
165c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    AddTrayItem(new TrayUserSeparator(this));
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
169c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  tray_accessibility_ = new TrayAccessibility(this);
170c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  tray_date_ = new TrayDate(this);
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS)
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AddTrayItem(new TraySessionLengthLimit(this));
174c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayEnterprise(this));
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  AddTrayItem(new TraySupervisedUser(this));
176c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayIME(this));
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddTrayItem(tray_accessibility_);
178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayTracing(this));
179c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayPower(this, message_center::MessageCenter::Get()));
180c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayNetwork(this));
181c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayVPN(this));
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TraySms(this));
183c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayBluetooth(this));
184c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayDisplay(this));
18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  screen_capture_tray_item_ = new ScreenCaptureTrayItem(this);
18603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  AddTrayItem(screen_capture_tray_item_);
18703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  screen_share_tray_item_ = new ScreenShareTrayItem(this);
18803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  AddTrayItem(screen_share_tray_item_);
189010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  AddTrayItem(new MultiProfileMediaTrayItem(this));
190c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayAudioChromeOs(this));
191c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayBrightness(this));
192c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayCapsLock(this));
193c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TraySettings(this));
194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayUpdate(this));
195a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  AddTrayItem(new TrayRotationLock(this));
1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  AddTrayItem(tray_date_);
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#elif defined(OS_WIN)
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AddTrayItem(tray_accessibility_);
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (media::CoreAudioUtil::IsSupported())
200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    AddTrayItem(new TrayAudioWin(this));
201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayUpdate(this));
2021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  AddTrayItem(tray_date_);
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#elif defined(OS_LINUX)
204c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayIME(this));
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AddTrayItem(tray_accessibility_);
206c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayBluetooth(this));
207c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AddTrayItem(new TrayUpdate(this));
2081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  AddTrayItem(tray_date_);
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetVisible(ash::Shell::GetInstance()->system_tray_delegate()->
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetTrayVisibilityOnStartup());
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::AddTrayItem(SystemTrayItem* item) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  items_.push_back(item);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* tray_item = item->CreateTrayView(delegate->GetUserLoginStatus());
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  item->UpdateAfterShelfAlignmentChange(shelf_alignment());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tray_item) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tray_container()->AddChildViewAt(tray_item, 0);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PreferredSizeChanged();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tray_item_map_[item] = tray_item;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::RemoveTrayItem(SystemTrayItem* item) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTIMPLEMENTED();
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst std::vector<SystemTrayItem*>& SystemTray::GetTrayItems() const {
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return items_.get();
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowDefaultView(BubbleCreationType creation_type) {
2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ShowDefaultViewWithOffset(
2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      creation_type,
2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      TrayBubbleView::InitParams::kArrowDefaultOffset,
2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      false);
2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void SystemTray::ShowPersistentDefaultView() {
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShowItems(items_.get(),
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            false,
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            false,
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            BUBBLE_CREATE_NEW,
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            TrayBubbleView::InitParams::kArrowDefaultOffset,
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            true);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowDetailedView(SystemTrayItem* item,
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int close_delay,
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  bool activate,
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  BubbleCreationType creation_type) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SystemTrayItem*> items;
258c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // The detailed view with timeout means a UI to show the current system state,
259c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // like the audio level or brightness. Such UI should behave as persistent and
260c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // keep its own logic for the appearance.
261c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool persistent = (
262c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      !activate && close_delay > 0 && creation_type == BUBBLE_CREATE_NEW);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  items.push_back(item);
264c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ShowItems(
265c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      items, true, activate, creation_type, GetTrayXOffset(item), persistent);
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (system_bubble_)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::SetDetailedViewCloseDelay(int close_delay) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DETAILED))
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_bubble_->bubble()->StartAutoCloseTimer(close_delay);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::HideDetailedView(SystemTrayItem* item) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (item != detailed_item_)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DestroySystemBubble();
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateNotificationBubble();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowNotificationView(SystemTrayItem* item) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (std::find(notification_items_.begin(), notification_items_.end(), item)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      != notification_items_.end())
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notification_items_.push_back(item);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateNotificationBubble();
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::HideNotificationView(SystemTrayItem* item) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SystemTrayItem*>::iterator found_iter =
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find(notification_items_.begin(), notification_items_.end(), item);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (found_iter == notification_items_.end())
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notification_items_.erase(found_iter);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only update the notification bubble if visible (i.e. don't create one).
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (notification_bubble_)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateNotificationBubble();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::UpdateAfterLoginStatusChange(user::LoginStatus login_status) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DestroySystemBubble();
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UpdateNotificationBubble();
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it != items_.end();
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++it) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*it)->UpdateAfterLoginStatusChange(login_status);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Items default to SHELF_ALIGNMENT_BOTTOM. Update them if the initial
3127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // position of the shelf differs.
3137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (shelf_alignment() != SHELF_ALIGNMENT_BOTTOM)
3147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    UpdateAfterShelfAlignmentChange(shelf_alignment());
3157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVisible(true);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PreferredSizeChanged();
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SystemTrayItem*>::iterator it = items_.begin();
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it != items_.end();
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++it) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*it)->UpdateAfterShelfAlignmentChange(alignment);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::SetHideNotifications(bool hide_notifications) {
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (notification_bubble_)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notification_bubble_->bubble()->SetVisible(!hide_notifications);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hide_notifications_ = hide_notifications;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool SystemTray::ShouldShowShelf() const {
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return system_bubble_.get() && system_bubble_->bubble()->ShouldShowShelf();
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::HasSystemBubble() const {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return system_bubble_.get() != NULL;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SystemTray::HasNotificationBubble() const {
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return notification_bubble_.get() != NULL;
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
346c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSystemTrayBubble* SystemTray::GetSystemBubble() {
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!system_bubble_)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return system_bubble_->bubble();
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::IsAnyBubbleVisible() const {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ((system_bubble_.get() &&
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           system_bubble_->bubble()->IsVisible()) ||
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (notification_bubble_.get() &&
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           notification_bubble_->bubble()->IsVisible()));
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::IsMouseInNotificationBubble() const {
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!notification_bubble_)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return notification_bubble_->bubble_view()->GetBoundsInScreen().Contains(
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Shell::GetScreen()->GetCursorScreenPoint());
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool SystemTray::CloseSystemBubble() const {
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!system_bubble_)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  system_bubble_->bubble()->Close();
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)views::View* SystemTray::GetHelpButtonView() const {
3741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return tray_date_->GetHelpButtonView();
3751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SystemTray::CloseNotificationBubbleForTest() const {
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!notification_bubble_)
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  notification_bubble_->bubble()->Close();
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Private methods.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::HasSystemBubbleType(SystemTrayBubble::BubbleType type) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(type != SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return system_bubble_.get() && system_bubble_->bubble_type() == type;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::DestroySystemBubble() {
3924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CloseSystemBubbleAndDeactivateSystemTray();
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  detailed_item_ = NULL;
394a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  UpdateWebNotifications();
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::DestroyNotificationBubble() {
398558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (notification_bubble_) {
399558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    notification_bubble_.reset();
400a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    UpdateWebNotifications();
401558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)base::string16 SystemTray::GetAccessibleNameForTray() {
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::string16 time = GetAccessibleTimeString(base::Time::Now());
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::string16 battery = base::ASCIIToUTF16("");
4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_CHROMEOS)
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  battery = PowerStatus::Get()->GetAccessibleNameString(false);
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return l10n_util::GetStringFUTF16(
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      IDS_ASH_STATUS_TRAY_ACCESSIBLE_DESCRIPTION, time, battery);
4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SystemTray::GetTrayXOffset(SystemTrayItem* item) const {
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't attempt to align the arrow if the shelf is on the left or right.
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (shelf_alignment() != SHELF_ALIGNMENT_BOTTOM &&
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      shelf_alignment() != SHELF_ALIGNMENT_TOP)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TrayBubbleView::InitParams::kArrowDefaultOffset;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<SystemTrayItem*, views::View*>::const_iterator it =
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tray_item_map_.find(item);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == tray_item_map_.end())
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TrayBubbleView::InitParams::kArrowDefaultOffset;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const views::View* item_view = it->second;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (item_view->bounds().IsEmpty()) {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The bounds of item could be still empty if it does not have a visible
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // tray view. In that case, use the default (minimum) offset.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TrayBubbleView::InitParams::kArrowDefaultOffset;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point point(item_view->width() / 2, 0);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConvertPointToWidget(item_view, &point);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return point.x();
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowDefaultViewWithOffset(BubbleCreationType creation_type,
4381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                           int arrow_offset,
4391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                           bool persistent) {
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (creation_type != BUBBLE_USE_EXISTING) {
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Shell::GetInstance()->metrics()->RecordUserMetricsAction(
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ash::UMA_STATUS_AREA_MENU_OPENED);
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ShowItems(items_.get(), false, true, creation_type, arrow_offset, persistent);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items,
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           bool detailed,
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           bool can_activate,
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           BubbleCreationType creation_type,
4511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                           int arrow_offset,
4521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                           bool persistent) {
4537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // No system tray bubbles in kiosk mode.
4547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus() ==
4557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ash::user::LOGGED_IN_KIOSK_APP) {
4567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
4577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Destroy any existing bubble and create a new one.
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SystemTrayBubble::BubbleType bubble_type = detailed ?
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SystemTrayBubble::BUBBLE_TYPE_DETAILED :
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SystemTrayBubble::BUBBLE_TYPE_DEFAULT;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Destroy the notification bubble here so that it doesn't get rebuilt
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // while we add items to the main bubble_ (e.g. in HideNotificationView).
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notification_bubble_.reset();
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (system_bubble_.get() && creation_type == BUBBLE_USE_EXISTING) {
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_bubble_->bubble()->UpdateView(items, bubble_type);
469a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // If ChromeVox is enabled, focus the default item if no item is focused.
470a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (Shell::GetInstance()->accessibility_delegate()->
471a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        IsSpokenFeedbackEnabled()) {
472a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      system_bubble_->bubble()->FocusDefaultIfNeeded();
473a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
475558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // Remember if the menu is a single property (like e.g. volume) or the
476558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // full tray menu. Note that in case of the |BUBBLE_USE_EXISTING| case
477558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // above, |full_system_tray_menu_| does not get changed since the fact that
478558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // the menu is full (or not) doesn't change even if a "single property"
479558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // (like network) replaces most of the menu.
480558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    full_system_tray_menu_ = items.size() > 1;
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The menu width is fixed, and it is a per language setting.
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int menu_width = std::max(kMinimumSystemTrayMenuWidth,
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Shell::GetInstance()->system_tray_delegate()->GetSystemTrayMenuWidth());
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TrayBubbleView::InitParams init_params(TrayBubbleView::ANCHOR_TYPE_TRAY,
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           GetAnchorAlignment(),
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           menu_width,
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           kTrayPopupMaxWidth);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    init_params.can_activate = can_activate;
490a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    init_params.first_item_has_no_margin = true;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (detailed) {
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is the case where a volume control or brightness control bubble
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // is created.
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      init_params.max_height = default_bubble_height_;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      init_params.arrow_color = kBackgroundColor;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      init_params.arrow_color = kHeaderBackgroundColor;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    init_params.arrow_offset = arrow_offset;
5001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (bubble_type == SystemTrayBubble::BUBBLE_TYPE_DEFAULT)
5011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      init_params.close_on_deactivate = !persistent;
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // For Volume and Brightness we don't want to show an arrow when
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // they are shown in a bubble by themselves.
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    init_params.arrow_paint_type = views::BubbleBorder::PAINT_NORMAL;
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (items.size() == 1 && items[0]->ShouldHideArrow())
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      init_params.arrow_paint_type = views::BubbleBorder::PAINT_TRANSPARENT;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SystemTrayBubble* bubble = new SystemTrayBubble(this, items, bubble_type);
508c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    system_bubble_.reset(new SystemBubbleWrapper(bubble));
5091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    system_bubble_->InitView(this, tray_container(), &init_params, persistent);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save height of default view for creating detailed views directly.
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!detailed)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_bubble_height_ = system_bubble_->bubble_view()->height();
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (detailed && items.size() > 0)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    detailed_item_ = items[0];
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    detailed_item_ = NULL;
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateNotificationBubble();  // State changed, re-create notifications.
521a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!notification_bubble_)
522a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    UpdateWebNotifications();
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetShelfLayoutManager()->UpdateAutoHideState();
52458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
52558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // When we show the system menu in our alternate shelf layout, we need to
52658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // tint the background.
52758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (full_system_tray_menu_)
52858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    SetDrawBackgroundAsActive(true);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::UpdateNotificationBubble() {
532bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Only show the notification bubble if we have notifications.
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (notification_items_.empty()) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DestroyNotificationBubble();
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Destroy the existing bubble before constructing a new one.
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notification_bubble_.reset();
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SystemTrayBubble* notification_bubble;
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  notification_bubble = new SystemTrayBubble(
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, notification_items_, SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION);
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* anchor;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TrayBubbleView::AnchorType anchor_type;
544868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Tray items might want to show notifications while we are creating and
545868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // initializing the |system_bubble_| - but it might not be fully initialized
546868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // when coming here - this would produce a crashed like crbug.com/247416.
547868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // As such we check the existence of the widget here.
548868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (system_bubble_.get() &&
549868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      system_bubble_->bubble_view() &&
550868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      system_bubble_->bubble_view()->GetWidget()) {
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    anchor = system_bubble_->bubble_view();
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    anchor_type = TrayBubbleView::ANCHOR_TYPE_BUBBLE;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    anchor = tray_container();
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    anchor_type = TrayBubbleView::ANCHOR_TYPE_TRAY;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TrayBubbleView::InitParams init_params(anchor_type,
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         GetAnchorAlignment(),
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         kTrayPopupMinWidth,
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         kTrayPopupMaxWidth);
561a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  init_params.first_item_has_no_margin = true;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  init_params.arrow_color = kBackgroundColor;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  init_params.arrow_offset = GetTrayXOffset(notification_items_[0]);
564c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  notification_bubble_.reset(new SystemBubbleWrapper(notification_bubble));
5651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  notification_bubble_->InitView(this, anchor, &init_params, false);
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (notification_bubble->bubble_view()->child_count() == 0) {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // It is possible that none of the items generated actual notifications.
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DestroyNotificationBubble();
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hide_notifications_)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notification_bubble->SetVisible(false);
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
575a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    UpdateWebNotifications();
576a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
577a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
578a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void SystemTray::UpdateWebNotifications() {
579a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  TrayBubbleView* bubble_view = NULL;
580a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (notification_bubble_)
581a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    bubble_view = notification_bubble_->bubble_view();
582a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  else if (system_bubble_)
583a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    bubble_view = system_bubble_->bubble_view();
584a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
585a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int height = 0;
586a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (bubble_view) {
587a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
588a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        bubble_view->GetWidget()->GetNativeView()).work_area();
589a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (GetShelfLayoutManager()->GetAlignment() != SHELF_ALIGNMENT_TOP) {
590a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      height = std::max(
591a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          0, work_area.height() - bubble_view->GetBoundsInScreen().y());
592a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    } else {
593a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      height = std::max(
594a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          0, bubble_view->GetBoundsInScreen().bottom() - work_area.y());
595a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
596a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
597a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  status_area_widget()->web_notification_tray()->SetSystemTrayHeight(height);
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)base::string16 SystemTray::GetAccessibleTimeString(
6015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const base::Time& now) const {
6025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::HourClockType hour_type =
6035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ash::Shell::GetInstance()->system_tray_delegate()->GetHourClockType();
6045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return base::TimeFormatTimeOfDayWithHourClockType(
6055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      now, hour_type, base::kKeepAmPm);
6065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
6075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::SetShelfAlignment(ShelfAlignment alignment) {
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alignment == shelf_alignment())
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
611c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  TrayBackgroundView::SetShelfAlignment(alignment);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateAfterShelfAlignmentChange(alignment);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Destroy any existing bubble so that it is rebuilt correctly.
6144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CloseSystemBubbleAndDeactivateSystemTray();
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rebuild any notification bubble.
616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (notification_bubble_) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notification_bubble_.reset();
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateNotificationBubble();
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::AnchorUpdated() {
623c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (notification_bubble_) {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notification_bubble_->bubble_view()->UpdateBubble();
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Ensure that the notification buble is above the shelf/status area.
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notification_bubble_->bubble_view()->GetWidget()->StackAtTop();
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateBubbleViewArrow(notification_bubble_->bubble_view());
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (system_bubble_) {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_bubble_->bubble_view()->UpdateBubble();
631a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    UpdateBubbleViewArrow(system_bubble_->bubble_view());
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void SystemTray::BubbleResized(const TrayBubbleView* bubble_view) {
636d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  UpdateWebNotifications();
637d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
638d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::HideBubbleWithView(const TrayBubbleView* bubble_view) {
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (system_bubble_.get() && bubble_view == system_bubble_->bubble_view()) {
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DestroySystemBubble();
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateNotificationBubble();  // State changed, re-create notifications.
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetShelfLayoutManager()->UpdateAutoHideState();
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (notification_bubble_.get() &&
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             bubble_view == notification_bubble_->bubble_view()) {
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DestroyNotificationBubble();
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::ClickedOutsideBubble() {
6511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!system_bubble_ || system_bubble_->is_persistent())
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HideBubbleWithView(system_bubble_->bubble_view());
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::BubbleViewDestroyed() {
658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (system_bubble_) {
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_bubble_->bubble()->DestroyItemViews();
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_bubble_->bubble()->BubbleViewDestroyed();
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::OnMouseEnteredView() {
665c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (system_bubble_)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_bubble_->bubble()->StopAutoCloseTimer();
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::OnMouseExitedView() {
670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (system_bubble_)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_bubble_->bubble()->RestartAutoCloseTimer();
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
674c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::string16 SystemTray::GetAccessibleNameForBubble() {
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetAccessibleNameForTray();
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect SystemTray::GetAnchorRect(
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::Widget* anchor_widget,
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TrayBubbleView::AnchorType anchor_type,
681cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    TrayBubbleView::AnchorAlignment anchor_alignment) const {
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetBubbleAnchorRect(anchor_widget, anchor_type, anchor_alignment);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTray::HideBubble(const TrayBubbleView* bubble_view) {
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HideBubbleWithView(bubble_view);
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)views::View* SystemTray::GetTrayItemViewForTest(SystemTrayItem* item) {
6904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::map<SystemTrayItem*, views::View*>::iterator it =
6914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      tray_item_map_.find(item);
6924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return it == tray_item_map_.end() ? NULL : it->second;
6934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
695c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTrayDate* SystemTray::GetTrayDateForTesting() const { return tray_date_; }
6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTray::PerformAction(const ui::Event& event) {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're already showing the default view, hide it; otherwise, show it
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (and hide any popup that's currently shown).
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) {
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_bubble_->bubble()->Close();
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int arrow_offset = TrayBubbleView::InitParams::kArrowDefaultOffset;
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (event.IsMouseEvent() || event.type() == ui::ET_GESTURE_TAP) {
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const ui::LocatedEvent& located_event =
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<const ui::LocatedEvent&>(event);
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM ||
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          shelf_alignment() == SHELF_ALIGNMENT_TOP) {
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gfx::Point point(located_event.x(), 0);
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ConvertPointToWidget(this, &point);
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        arrow_offset = point.x();
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset, false);
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SystemTray::CloseSystemBubbleAndDeactivateSystemTray() {
7204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  system_bubble_.reset();
7214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // When closing a system bubble with the alternate shelf layout, we need to
7224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // turn off the active tinting of the shelf.
7234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (full_system_tray_menu_) {
7244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SetDrawBackgroundAsActive(false);
7254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    full_system_tray_menu_ = false;
7264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
7274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
730