Commit 2a5c5f06 authored by zturner@chromium.org's avatar zturner@chromium.org

Refactor the TrayAudio code so that it can be used by other platforms.

The motivation here is to introduce the volume slider tray UI into
Windows Ash.

This change does not actually add tray audio UI to other platforms,
only moves some non-chromeos specific things out of the chromeos
platform folders, so that we can hook in the native Audio APIs
of other platforms to the tray UI.

At a high level, this change does the following:

1) Move tray_audio out of chromeos/ so that other platforms can
use the UI that it provides.
2) Decouples TrayAudio from CrasAudioHandler by introducing a
new delegate, in a similar vein to what is done with all the other
handlers (e.g. the BluetoothHandler)
3) Move the additional views (VolumeView, etc) to their own files
so they can be used by other platforms as well.

TEST=
 On CrOS physical device, verified that:
 1) Keyboard volume buttons function appropriately and display the
    volume view
 2) AudioDetailView still is accessible at the correct times
 3) Adjusting the volume (via the keyboard shortcuts or via the
    slider) correctly change the output volume.
 4) UI still behaves correctly (e.g. icons update as the volume
    changes, mute button works, etc).

BUG=227247

Review URL: https://codereview.chromium.org/163953007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251959 0039d316-1c4b-4281-b951-d872f2087c98
parent 7c82539c
...@@ -266,12 +266,22 @@ ...@@ -266,12 +266,22 @@
'sticky_keys/sticky_keys_controller.h', 'sticky_keys/sticky_keys_controller.h',
'sticky_keys/sticky_keys_overlay.cc', 'sticky_keys/sticky_keys_overlay.cc',
'sticky_keys/sticky_keys_overlay.h', 'sticky_keys/sticky_keys_overlay.h',
'system/audio/audio_observer.h',
'system/audio/tray_audio.cc',
'system/audio/tray_audio.h',
'system/audio/tray_audio_delegate.h',
'system/audio/volume_view.cc',
'system/audio/volume_view.h',
'system/bluetooth/bluetooth_observer.h', 'system/bluetooth/bluetooth_observer.h',
'system/bluetooth/tray_bluetooth.cc', 'system/bluetooth/tray_bluetooth.cc',
'system/bluetooth/tray_bluetooth.h', 'system/bluetooth/tray_bluetooth.h',
'system/brightness_control_delegate.h', 'system/brightness_control_delegate.h',
'system/chromeos/audio/tray_audio.cc', 'system/chromeos/audio/audio_detailed_view.cc',
'system/chromeos/audio/tray_audio.h', 'system/chromeos/audio/audio_detailed_view.h',
'system/chromeos/audio/tray_audio_chromeos.cc',
'system/chromeos/audio/tray_audio_chromeos.h',
'system/chromeos/audio/tray_audio_delegate_chromeos.cc',
'system/chromeos/audio/tray_audio_delegate_chromeos.h',
'system/chromeos/enterprise/enterprise_domain_observer.h', 'system/chromeos/enterprise/enterprise_domain_observer.h',
'system/chromeos/brightness/brightness_controller_chromeos.cc', 'system/chromeos/brightness/brightness_controller_chromeos.cc',
'system/chromeos/brightness/brightness_controller_chromeos.h', 'system/chromeos/brightness/brightness_controller_chromeos.h',
......
...@@ -256,12 +256,16 @@ bool UseDockedWindows() { ...@@ -256,12 +256,16 @@ bool UseDockedWindows() {
return !CommandLine::ForCurrentProcess()->HasSwitch(kAshDisableDockedWindows); return !CommandLine::ForCurrentProcess()->HasSwitch(kAshDisableDockedWindows);
} }
#if defined(OS_CHROMEOS)
bool ShowAudioDeviceMenu() { bool ShowAudioDeviceMenu() {
#if defined(OS_CHROMEOS)
return !CommandLine::ForCurrentProcess()-> return !CommandLine::ForCurrentProcess()->
HasSwitch(kAshDisableAudioDeviceMenu); HasSwitch(kAshDisableAudioDeviceMenu);
#else
return false;
#endif
} }
#if defined(OS_CHROMEOS)
bool UseUsbChargerNotification() { bool UseUsbChargerNotification() {
return !CommandLine::ForCurrentProcess()-> return !CommandLine::ForCurrentProcess()->
HasSwitch(kAshDisableUsbChargerNotification); HasSwitch(kAshDisableUsbChargerNotification);
......
...@@ -101,10 +101,10 @@ ASH_EXPORT bool UseOverviewMode(); ...@@ -101,10 +101,10 @@ ASH_EXPORT bool UseOverviewMode();
// Returns true if docked windows feature is enabled. // Returns true if docked windows feature is enabled.
ASH_EXPORT bool UseDockedWindows(); ASH_EXPORT bool UseDockedWindows();
#if defined(OS_CHROMEOS)
// Returns true if we should show the audio device switching UI. // Returns true if we should show the audio device switching UI.
ASH_EXPORT bool ShowAudioDeviceMenu(); ASH_EXPORT bool ShowAudioDeviceMenu();
#if defined(OS_CHROMEOS)
// Returns true if a notification should appear when a low-power USB charger // Returns true if a notification should appear when a low-power USB charger
// is connected. // is connected.
ASH_EXPORT bool UseUsbChargerNotification(); ASH_EXPORT bool UseUsbChargerNotification();
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_AUDIO_AUDIO_OBSERVER_H_
#define ASH_SYSTEM_AUDIO_AUDIO_OBSERVER_H_
namespace ash {
class AudioObserver {
public:
virtual ~AudioObserver() {}
// Called when output volume changed.
virtual void OnOutputVolumeChanged() = 0;
// Called when output mute state changed.
virtual void OnOutputMuteChanged() = 0;
// Called when audio nodes changed.
virtual void OnAudioNodesChanged() = 0;
// Called when active audio output node changed.
virtual void OnActiveOutputNodeChanged() = 0;
// Called when active audio input node changed.
virtual void OnActiveInputNodeChanged() = 0;
};
} // namespace ash
#endif // ASH_SYSTEM_AUDIO_AUDIO_OBSERVER_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/audio/tray_audio.h"
#include <cmath>
#include "ash/ash_constants.h"
#include "ash/ash_switches.h"
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/shell.h"
#include "ash/system/audio/tray_audio_delegate.h"
#include "ash/system/audio/volume_view.h"
#include "ash/system/tray/actionable_view.h"
#include "ash/system/tray/fixed_sized_scroll_view.h"
#include "ash/system/tray/hover_highlight_view.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/volume_control_delegate.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/ash_resources.h"
#include "grit/ash_strings.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/slider.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
namespace ash {
namespace internal {
TrayAudio::TrayAudio(SystemTray* system_tray,
system::TrayAudioDelegate* audio_delegate)
: TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_VOLUME_MUTE),
audio_delegate_(audio_delegate),
volume_view_(NULL),
pop_up_volume_view_(false) {
Shell::GetInstance()->system_tray_notifier()->AddAudioObserver(this);
}
TrayAudio::~TrayAudio() {
Shell::GetInstance()->system_tray_notifier()->RemoveAudioObserver(this);
}
bool TrayAudio::GetInitialVisibility() {
return audio_delegate_->IsOutputAudioMuted();
}
views::View* TrayAudio::CreateDefaultView(user::LoginStatus status) {
volume_view_ = new tray::VolumeView(this, audio_delegate_, true);
return volume_view_;
}
views::View* TrayAudio::CreateDetailedView(user::LoginStatus status) {
volume_view_ = new tray::VolumeView(this, audio_delegate_, false);
return volume_view_;
}
void TrayAudio::DestroyDefaultView() {
volume_view_ = NULL;
}
void TrayAudio::DestroyDetailedView() {
if (volume_view_) {
volume_view_ = NULL;
pop_up_volume_view_ = false;
}
}
bool TrayAudio::ShouldHideArrow() const {
return true;
}
bool TrayAudio::ShouldShowShelf() const {
return ash::switches::ShowAudioDeviceMenu() && !pop_up_volume_view_;
}
void TrayAudio::OnOutputVolumeChanged() {
float percent =
static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f;
if (tray_view())
tray_view()->SetVisible(GetInitialVisibility());
if (volume_view_) {
volume_view_->SetVolumeLevel(percent);
SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds);
return;
}
pop_up_volume_view_ = true;
PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false);
}
void TrayAudio::OnOutputMuteChanged() {
if (tray_view())
tray_view()->SetVisible(GetInitialVisibility());
if (volume_view_) {
volume_view_->Update();
SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds);
} else {
pop_up_volume_view_ = true;
PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false);
}
}
void TrayAudio::OnAudioNodesChanged() {
Update();
}
void TrayAudio::OnActiveOutputNodeChanged() {
Update();
}
void TrayAudio::OnActiveInputNodeChanged() {
Update();
}
void TrayAudio::Update() {
if (tray_view())
tray_view()->SetVisible(GetInitialVisibility());
if (volume_view_) {
volume_view_->SetVolumeLevel(
static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f);
volume_view_->Update();
}
}
} // namespace internal
} // namespace ash
// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef ASH_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_H_ #ifndef ASH_SYSTEM_AUDIO_TRAY_AUDIO_H_
#define ASH_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_H_ #define ASH_SYSTEM_AUDIO_TRAY_AUDIO_H_
#include "ash/system/audio/audio_observer.h"
#include "ash/system/tray/tray_image_item.h" #include "ash/system/tray/tray_image_item.h"
#include "chromeos/audio/cras_audio_handler.h"
namespace ash { namespace ash {
namespace system {
class TrayAudioDelegate;
}
namespace internal { namespace internal {
namespace tray { namespace tray {
class VolumeView; class VolumeView;
class AudioDetailedView;
} }
class TrayAudio : public TrayImageItem, class TrayAudio : public TrayImageItem,
public chromeos::CrasAudioHandler::AudioObserver { public AudioObserver {
public: public:
explicit TrayAudio(SystemTray* system_tray); TrayAudio(SystemTray* system_tray, system::TrayAudioDelegate* audio_delegate);
virtual ~TrayAudio(); virtual ~TrayAudio();
protected:
virtual void Update();
system::TrayAudioDelegate* audio_delegate_;
tray::VolumeView* volume_view_;
// True if VolumeView should be created for accelerator pop up;
// Otherwise, it should be created for detailed view in ash tray bubble.
bool pop_up_volume_view_;
private: private:
// Overridden from TrayImageItem. // Overridden from TrayImageItem.
virtual bool GetInitialVisibility() OVERRIDE; virtual bool GetInitialVisibility() OVERRIDE;
...@@ -34,28 +48,17 @@ class TrayAudio : public TrayImageItem, ...@@ -34,28 +48,17 @@ class TrayAudio : public TrayImageItem,
virtual bool ShouldHideArrow() const OVERRIDE; virtual bool ShouldHideArrow() const OVERRIDE;
virtual bool ShouldShowShelf() const OVERRIDE; virtual bool ShouldShowShelf() const OVERRIDE;
// Overridden from chromeos::CrasAudioHandler::AudioObserver. // Overridden from AudioObserver.
virtual void OnOutputVolumeChanged() OVERRIDE; virtual void OnOutputVolumeChanged() OVERRIDE;
virtual void OnOutputMuteChanged() OVERRIDE; virtual void OnOutputMuteChanged() OVERRIDE;
virtual void OnInputGainChanged() OVERRIDE;
virtual void OnInputMuteChanged() OVERRIDE;
virtual void OnAudioNodesChanged() OVERRIDE; virtual void OnAudioNodesChanged() OVERRIDE;
virtual void OnActiveOutputNodeChanged() OVERRIDE; virtual void OnActiveOutputNodeChanged() OVERRIDE;
virtual void OnActiveInputNodeChanged() OVERRIDE; virtual void OnActiveInputNodeChanged() OVERRIDE;
void Update();
tray::VolumeView* volume_view_;
tray::AudioDetailedView* audio_detail_;
// True if VolumeView should be created for accelerator pop up;
// Otherwise, it should be created for detailed view in ash tray bubble.
bool pop_up_volume_view_;
DISALLOW_COPY_AND_ASSIGN(TrayAudio); DISALLOW_COPY_AND_ASSIGN(TrayAudio);
}; };
} // namespace internal } // namespace internal
} // namespace ash } // namespace ash
#endif // ASH_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_H_ #endif // ASH_SYSTEM_AUDIO_TRAY_AUDIO_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_H_
#define ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_H_
namespace ash {
namespace system {
class TrayAudioDelegate {
public:
enum { kNoAudioDeviceIcon = -1 };
virtual ~TrayAudioDelegate() {}
// Sets the volume level of the output device to the minimum level which is
// deemed to be audible.
virtual void AdjustOutputVolumeToAudibleLevel() = 0;
// Gets the default level in the range 0%-100% at which the output device
// should be muted.
virtual int GetOutputDefaultVolumeMuteLevel() = 0;
// Gets the icon to use for the active output device.
virtual int GetActiveOutputDeviceIconId() = 0;
// Returns the volume level of the output device in the range 0%-100%.
virtual int GetOutputVolumeLevel() = 0;
// Returns true if the device has alternative inputs or outputs.
virtual bool HasAlternativeSources() = 0;
// Returns whether the output volume is muted.
virtual bool IsOutputAudioMuted() = 0;
// Sets the mute state of the output device.
virtual void SetOutputAudioIsMuted(bool is_muted) = 0;
// Sets the volume level of the output device in the range 0%-100%
virtual void SetOutputVolumeLevel(int level) = 0;
};
} // namespace system
} // namespace ash
#endif // ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/audio/volume_view.h"
#include "ash/ash_constants.h"
#include "ash/ash_switches.h"
#include "ash/shell.h"
#include "ash/system/audio/tray_audio_delegate.h"
#include "ash/system/tray/system_tray_item.h"
#include "ash/system/tray/tray_constants.h"
#include "grit/ash_resources.h"
#include "grit/ash_strings.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/layout/box_layout.h"
namespace {
const int kVolumeImageWidth = 25;
const int kVolumeImageHeight = 25;
const int kBarSeparatorWidth = 25;
const int kBarSeparatorHeight = 30;
const int kSliderRightPaddingToVolumeViewEdge = 17;
const int kExtraPaddingBetweenBarAndMore = 10;
// IDR_AURA_UBER_TRAY_VOLUME_LEVELS contains 5 images,
// The one for mute is at the 0 index and the other
// four are used for ascending volume levels.
const int kVolumeLevels = 4;
} // namespace
namespace ash {
namespace internal {
namespace tray {
class VolumeButton : public views::ToggleImageButton {
public:
VolumeButton(views::ButtonListener* listener,
system::TrayAudioDelegate* audio_delegate)
: views::ToggleImageButton(listener),
audio_delegate_(audio_delegate),
image_index_(-1) {
SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE);
image_ = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_AURA_UBER_TRAY_VOLUME_LEVELS);
SetPreferredSize(gfx::Size(kTrayPopupItemHeight, kTrayPopupItemHeight));
Update();
}
virtual ~VolumeButton() {}
void Update() {
float level =
static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f;
int image_index = audio_delegate_->IsOutputAudioMuted() ?
0 : (level == 1.0 ?
kVolumeLevels :
std::max(1, int(std::ceil(level * (kVolumeLevels - 1)))));
if (image_index != image_index_) {
gfx::Rect region(0, image_index * kVolumeImageHeight,
kVolumeImageWidth, kVolumeImageHeight);
gfx::ImageSkia image_skia = gfx::ImageSkiaOperations::ExtractSubset(
*(image_.ToImageSkia()), region);
SetImage(views::CustomButton::STATE_NORMAL, &image_skia);
image_index_ = image_index;
}
SchedulePaint();
}
private:
// Overridden from views::View.
virtual gfx::Size GetPreferredSize() OVERRIDE {
gfx::Size size = views::ToggleImageButton::GetPreferredSize();
size.set_height(kTrayPopupItemHeight);
return size;
}
system::TrayAudioDelegate* audio_delegate_;
gfx::Image image_;
int image_index_;
DISALLOW_COPY_AND_ASSIGN(VolumeButton);
};
class VolumeSlider : public views::Slider {
public:
VolumeSlider(views::SliderListener* listener,
system::TrayAudioDelegate* audio_delegate)
: views::Slider(listener, views::Slider::HORIZONTAL),
audio_delegate_(audio_delegate) {
set_focus_border_color(kFocusBorderColor);
SetValue(
static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f);
SetAccessibleName(
ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
IDS_ASH_STATUS_TRAY_VOLUME));
Update();
}
virtual ~VolumeSlider() {}
void Update() {
UpdateState(!audio_delegate_->IsOutputAudioMuted());
}
private:
system::TrayAudioDelegate* audio_delegate_;
DISALLOW_COPY_AND_ASSIGN(VolumeSlider);
};
// Vertical bar separator that can be placed on the VolumeView.
class BarSeparator : public views::View {
public:
BarSeparator() {}
virtual ~BarSeparator() {}
// Overriden from views::View.
virtual gfx::Size GetPreferredSize() OVERRIDE {
return gfx::Size(kBarSeparatorWidth, kBarSeparatorHeight);
}
private:
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
canvas->FillRect(gfx::Rect(width() / 2, 0, 1, height()),
kButtonStrokeColor);
}
DISALLOW_COPY_AND_ASSIGN(BarSeparator);
};
VolumeView::VolumeView(SystemTrayItem* owner,
system::TrayAudioDelegate* audio_delegate,
bool is_default_view)
: owner_(owner),
audio_delegate_(audio_delegate),
icon_(NULL),
slider_(NULL),
bar_(NULL),
device_type_(NULL),
more_(NULL),
is_default_view_(is_default_view) {
SetFocusable(false);
SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
kTrayPopupPaddingHorizontal, 0, kTrayPopupPaddingBetweenItems));
icon_ = new VolumeButton(this, audio_delegate_);
AddChildView(icon_);
slider_ = new VolumeSlider(this, audio_delegate_);
AddChildView(slider_);
bar_ = new BarSeparator;
AddChildView(bar_);
device_type_ = new views::ImageView;
AddChildView(device_type_);
more_ = new views::ImageView;
more_->EnableCanvasFlippingForRTLUI(true);
more_->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_AURA_UBER_TRAY_MORE).ToImageSkia());
AddChildView(more_);
Update();
}
VolumeView::~VolumeView() {
}
void VolumeView::Update() {
icon_->Update();
slider_->Update();
UpdateDeviceTypeAndMore();
Layout();
}
void VolumeView::SetVolumeLevel(float percent) {
// Slider's value is in finer granularity than audio volume level(0.01),
// there will be a small discrepancy between slider's value and volume level
// on audio side. To avoid the jittering in slider UI, do not set change
// slider value if the change is less than 1%.
if (std::abs(percent-slider_->value()) < 0.01)
return;
// The change in volume will be reflected via accessibility system events,
// so we prevent the UI event from being sent here.
slider_->set_enable_accessibility_events(false);
slider_->SetValue(percent);
// It is possible that the volume was (un)muted, but the actual volume level
// did not change. In that case, setting the value of the slider won't
// trigger an update. So explicitly trigger an update.
Update();
slider_->set_enable_accessibility_events(true);
}
void VolumeView::UpdateDeviceTypeAndMore() {
if (!ash::switches::ShowAudioDeviceMenu() || !is_default_view_) {
more_->SetVisible(false);
bar_->SetVisible(false);
device_type_->SetVisible(false);
return;
}
bool show_more = audio_delegate_->HasAlternativeSources();
more_->SetVisible(show_more);
bar_->SetVisible(show_more);
// Show output device icon if necessary.
int device_icon = audio_delegate_->GetActiveOutputDeviceIconId();
if (device_icon != system::TrayAudioDelegate::kNoAudioDeviceIcon) {
device_type_->SetVisible(true);
device_type_->SetImage(
ui::ResourceBundle::GetSharedInstance().GetImageNamed(
device_icon).ToImageSkia());
} else {
device_type_->SetVisible(false);
}
}
void VolumeView::HandleVolumeUp(float level) {
audio_delegate_->SetOutputVolumeLevel(level);
if (audio_delegate_->IsOutputAudioMuted() &&
level > audio_delegate_->GetOutputDefaultVolumeMuteLevel()) {
audio_delegate_->SetOutputAudioIsMuted(false);
}
}
void VolumeView::HandleVolumeDown(float level) {
audio_delegate_->SetOutputVolumeLevel(level);
if (!audio_delegate_->IsOutputAudioMuted() &&
level <= audio_delegate_->GetOutputDefaultVolumeMuteLevel()) {
audio_delegate_->SetOutputAudioIsMuted(true);
} else if (audio_delegate_->IsOutputAudioMuted() &&
level > audio_delegate_->GetOutputDefaultVolumeMuteLevel()) {
audio_delegate_->SetOutputAudioIsMuted(false);
}
}
void VolumeView::Layout() {
views::View::Layout();
if (!more_->visible()) {
int w = width() - slider_->bounds().x() -
kSliderRightPaddingToVolumeViewEdge;
slider_->SetSize(gfx::Size(w, slider_->height()));
return;
}
// Make sure the chevron always has the full size.
gfx::Size size = more_->GetPreferredSize();
gfx::Rect bounds(size);
bounds.set_x(width() - size.width() - kTrayPopupPaddingBetweenItems);
bounds.set_y((height() - size.height()) / 2);
more_->SetBoundsRect(bounds);
// Layout either bar_ or device_type_ at the left of the more_ button.
views::View* view_left_to_more;
if (device_type_->visible())
view_left_to_more = device_type_;
else
view_left_to_more = bar_;
gfx::Size view_size = view_left_to_more->GetPreferredSize();
gfx::Rect view_bounds(view_size);
view_bounds.set_x(more_->bounds().x() - view_size.width() -
kExtraPaddingBetweenBarAndMore);
view_bounds.set_y((height() - view_size.height()) / 2);
view_left_to_more->SetBoundsRect(view_bounds);
// Layout vertical bar next to view_left_to_more if device_type_ is visible.
if (device_type_->visible()) {
gfx::Size bar_size = bar_->GetPreferredSize();
gfx::Rect bar_bounds(bar_size);
bar_bounds.set_x(view_left_to_more->bounds().x() - bar_size.width());
bar_bounds.set_y((height() - bar_size.height()) / 2);
bar_->SetBoundsRect(bar_bounds);
}
// Layout slider, calculate slider width.
gfx::Rect slider_bounds = slider_->bounds();
slider_bounds.set_width(
bar_->bounds().x()
- (device_type_->visible() ? 0 : kTrayPopupPaddingBetweenItems)
- slider_bounds.x());
slider_->SetBoundsRect(slider_bounds);
}
void VolumeView::ButtonPressed(views::Button* sender, const ui::Event& event) {
CHECK(sender == icon_);
bool mute_on = !audio_delegate_->IsOutputAudioMuted();
audio_delegate_->SetOutputAudioIsMuted(mute_on);
if (!mute_on)
audio_delegate_->AdjustOutputVolumeToAudibleLevel();
icon_->Update();
}
void VolumeView::SliderValueChanged(views::Slider* sender,
float value,
float old_value,
views::SliderChangeReason reason) {
if (reason == views::VALUE_CHANGED_BY_USER) {
float new_volume = value * 100.0f;
float current_volume = audio_delegate_->GetOutputVolumeLevel();
// Do not call change audio volume if the difference is less than
// 1%, which is beyond cras audio api's granularity for output volume.
if (std::abs(new_volume - current_volume) < 1.0f)
return;
Shell::GetInstance()->metrics()->RecordUserMetricsAction(
is_default_view_ ?
ash::UMA_STATUS_AREA_CHANGED_VOLUME_MENU :
ash::UMA_STATUS_AREA_CHANGED_VOLUME_POPUP);
if (new_volume > current_volume)
HandleVolumeUp(new_volume);
else
HandleVolumeDown(new_volume);
}
icon_->Update();
}
bool VolumeView::PerformAction(const ui::Event& event) {
if (!more_->visible())
return false;
owner_->TransitionDetailedView();
return true;
}
} // namespace tray
} // namespace internal
} // namespace ash
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_AUDIO_VOLUME_VIEW_H_
#define ASH_SYSTEM_AUDIO_VOLUME_VIEW_H_
#include "ash/system/tray/actionable_view.h"
#include "ui/gfx/font.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/slider.h"
namespace views {
class View;
class ImageView;
}
namespace ash {
class SystemTrayItem;
namespace system {
class TrayAudioDelegate;
}
namespace internal {
class HoverHighlightView;
namespace tray {
class BarSeparator;
class VolumeButton;
class VolumeSlider;
class VolumeView : public ActionableView,
public views::ButtonListener,
public views::SliderListener {
public:
VolumeView(SystemTrayItem* owner,
system::TrayAudioDelegate* audio_delegate,
bool is_default_view);
virtual ~VolumeView();
void Update();
// Sets volume level on slider_, |percent| is ranged from [0.00] to [1.00].
void SetVolumeLevel(float percent);
private:
// Updates bar_, device_type_ icon, and more_ buttons.
void UpdateDeviceTypeAndMore();
void HandleVolumeUp(float percent);
void HandleVolumeDown(float percent);
// Overridden from views::View.
virtual void Layout() OVERRIDE;
// Overridden from views::ButtonListener.
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
// Overridden from views::SliderListener.
virtual void SliderValueChanged(views::Slider* sender,
float value,
float old_value,
views::SliderChangeReason reason) OVERRIDE;
// Overriden from ActionableView.
virtual bool PerformAction(const ui::Event& event) OVERRIDE;
SystemTrayItem* owner_;
system::TrayAudioDelegate* audio_delegate_;
VolumeButton* icon_;
VolumeSlider* slider_;
BarSeparator* bar_;
views::ImageView* device_type_;
views::ImageView* more_;
bool is_default_view_;
DISALLOW_COPY_AND_ASSIGN(VolumeView);
};
} // namespace tray
} // namespace internal
} // namespace ash
#endif // ASH_SYSTEM_AUDIO_VOLUME_VIEW_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/chromeos/audio/audio_detailed_view.h"
#include "ash/system/tray/fixed_sized_scroll_view.h"
#include "ash/system/tray/hover_highlight_view.h"
#include "ash/system/tray/tray_constants.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "grit/ash_resources.h"
#include "grit/ash_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/border.h"
#include "ui/views/controls/label.h"
namespace {
base::string16 GetAudioDeviceName(const chromeos::AudioDevice& device) {
switch(device.type) {
case chromeos::AUDIO_TYPE_HEADPHONE:
return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_HEADPHONE);
case chromeos::AUDIO_TYPE_INTERNAL_SPEAKER:
return l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_SPEAKER);
case chromeos::AUDIO_TYPE_INTERNAL_MIC:
return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_MIC);
case chromeos::AUDIO_TYPE_USB:
return l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_AUDIO_USB_DEVICE,
base::UTF8ToUTF16(device.display_name));
case chromeos::AUDIO_TYPE_BLUETOOTH:
return l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_AUDIO_BLUETOOTH_DEVICE,
base::UTF8ToUTF16(device.display_name));
case chromeos::AUDIO_TYPE_HDMI:
return l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_AUDIO_HDMI_DEVICE,
base::UTF8ToUTF16(device.display_name));
default:
return base::UTF8ToUTF16(device.display_name);
}
}
} // namespace
using chromeos::CrasAudioHandler;
namespace ash {
namespace internal {
namespace tray {
AudioDetailedView::AudioDetailedView(SystemTrayItem* owner,
user::LoginStatus login)
: TrayDetailsView(owner),
login_(login) {
CreateItems();
Update();
}
AudioDetailedView::~AudioDetailedView() {
}
void AudioDetailedView::Update() {
UpdateAudioDevices();
Layout();
}
void AudioDetailedView::AddScrollListInfoItem(const base::string16& text) {
views::Label* label = new views::Label(
text,
ui::ResourceBundle::GetSharedInstance().GetFontList(
ui::ResourceBundle::BoldFont));
// Align info item with checkbox items
int margin = kTrayPopupPaddingHorizontal +
kTrayPopupDetailsLabelExtraLeftMargin;
int left_margin = 0;
int right_margin = 0;
if (base::i18n::IsRTL())
right_margin = margin;
else
left_margin = margin;
label->SetBorder(views::Border::CreateEmptyBorder(
ash::kTrayPopupPaddingBetweenItems,
left_margin,
ash::kTrayPopupPaddingBetweenItems,
right_margin));
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
label->SetEnabledColor(SkColorSetARGB(192, 0, 0, 0));
scroll_content()->AddChildView(label);
}
HoverHighlightView* AudioDetailedView::AddScrollListItem(
const base::string16& text,
gfx::Font::FontStyle style,
bool checked) {
HoverHighlightView* container = new HoverHighlightView(this);
container->AddCheckableLabel(text, style, checked);
scroll_content()->AddChildView(container);
return container;
}
void AudioDetailedView::CreateHeaderEntry() {
CreateSpecialRow(IDS_ASH_STATUS_TRAY_AUDIO, this);
}
void AudioDetailedView::CreateItems() {
CreateScrollableList();
CreateHeaderEntry();
}
void AudioDetailedView::UpdateAudioDevices() {
output_devices_.clear();
input_devices_.clear();
chromeos::AudioDeviceList devices;
CrasAudioHandler::Get()->GetAudioDevices(&devices);
for (size_t i = 0; i < devices.size(); ++i) {
if (devices[i].is_input)
input_devices_.push_back(devices[i]);
else
output_devices_.push_back(devices[i]);
}
UpdateScrollableList();
}
void AudioDetailedView::UpdateScrollableList() {
scroll_content()->RemoveAllChildViews(true);
device_map_.clear();
// Add audio output devices.
AddScrollListInfoItem(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_OUTPUT));
for (size_t i = 0; i < output_devices_.size(); ++i) {
HoverHighlightView* container = AddScrollListItem(
GetAudioDeviceName(output_devices_[i]),
gfx::Font::NORMAL,
output_devices_[i].active); /* checkmark if active */
device_map_[container] = output_devices_[i];
}
AddScrollSeparator();
// Add audio input devices.
AddScrollListInfoItem(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_INPUT));
for (size_t i = 0; i < input_devices_.size(); ++i) {
HoverHighlightView* container = AddScrollListItem(
GetAudioDeviceName(input_devices_[i]),
gfx::Font::NORMAL,
input_devices_[i].active); /* checkmark if active */
device_map_[container] = input_devices_[i];
}
scroll_content()->SizeToPreferredSize();
scroller()->Layout();
}
void AudioDetailedView::OnViewClicked(views::View* sender) {
if (sender == footer()->content()) {
TransitionToDefaultView();
} else {
AudioDeviceMap::iterator iter = device_map_.find(sender);
if (iter == device_map_.end())
return;
chromeos::AudioDevice& device = iter->second;
CrasAudioHandler::Get()->SwitchToDevice(device);
}
}
} // namespace tray
} // namespace internal
} // namespace ash
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_CHROMEOS_AUDIO_AUDIO_DETAILED_VIEW_H_
#define ASH_SYSTEM_CHROMEOS_AUDIO_AUDIO_DETAILED_VIEW_H_
#include "ash/system/tray/tray_details_view.h"
#include "ash/system/tray/view_click_listener.h"
#include "ash/system/user/login_status.h"
#include "chromeos/audio/audio_device.h"
#include "ui/gfx/font.h"
namespace views {
class View;
}
namespace ash {
namespace internal {
class HoverHighlightView;
namespace tray {
class AudioDetailedView : public TrayDetailsView,
public ViewClickListener {
public:
AudioDetailedView(SystemTrayItem* owner, user::LoginStatus login);
virtual ~AudioDetailedView();
void Update();
private:
void AddScrollListInfoItem(const base::string16& text);
HoverHighlightView* AddScrollListItem(const base::string16& text,
gfx::Font::FontStyle style,
bool checked);
void CreateHeaderEntry();
void CreateItems();
void UpdateScrollableList();
void UpdateAudioDevices();
// Overridden from ViewClickListener.
virtual void OnViewClicked(views::View* sender) OVERRIDE;
user::LoginStatus login_;
typedef std::map<views::View*, chromeos::AudioDevice> AudioDeviceMap;
chromeos::AudioDeviceList output_devices_;
chromeos::AudioDeviceList input_devices_;
AudioDeviceMap device_map_;
DISALLOW_COPY_AND_ASSIGN(AudioDetailedView);
};
} // namespace tray
} // namespace internal
} // namespace ash
#endif // ASH_SYSTEM_CHROMEOS_AUDIO_AUDIO_DETAILED_VIEW_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/chromeos/audio/tray_audio.h"
#include <cmath>
#include "ash/ash_constants.h"
#include "ash/ash_switches.h"
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/shell.h"
#include "ash/system/tray/actionable_view.h"
#include "ash/system/tray/fixed_sized_scroll_view.h"
#include "ash/system/tray/hover_highlight_view.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/volume_control_delegate.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "grit/ash_resources.h"
#include "grit/ash_strings.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/slider.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
using chromeos::CrasAudioHandler;
namespace ash {
namespace internal {
namespace {
const int kVolumeImageWidth = 25;
const int kVolumeImageHeight = 25;
const int kBarSeparatorWidth = 25;
const int kBarSeparatorHeight = 30;
const int kSliderRightPaddingToVolumeViewEdge = 17;
const int kExtraPaddingBetweenBarAndMore = 10;
const int kNoAudioDeviceIcon = -1;
// IDR_AURA_UBER_TRAY_VOLUME_LEVELS contains 5 images,
// The one for mute is at the 0 index and the other
// four are used for ascending volume levels.
const int kVolumeLevels = 4;
bool IsAudioMuted() {
return CrasAudioHandler::Get()->IsOutputMuted();
}
float GetVolumeLevel() {
return CrasAudioHandler::Get()->GetOutputVolumePercent() / 100.0f;
}
int GetAudioDeviceIconId(chromeos::AudioDeviceType type) {
if (type == chromeos::AUDIO_TYPE_HEADPHONE)
return IDR_AURA_UBER_TRAY_AUDIO_HEADPHONE;
else if (type == chromeos::AUDIO_TYPE_USB)
return IDR_AURA_UBER_TRAY_AUDIO_USB;
else if (type == chromeos::AUDIO_TYPE_BLUETOOTH)
return IDR_AURA_UBER_TRAY_AUDIO_BLUETOOTH;
else if (type == chromeos::AUDIO_TYPE_HDMI)
return IDR_AURA_UBER_TRAY_AUDIO_HDMI;
else
return kNoAudioDeviceIcon;
}
base::string16 GetAudioDeviceName(const chromeos::AudioDevice& device) {
switch(device.type) {
case chromeos::AUDIO_TYPE_HEADPHONE:
return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_HEADPHONE);
case chromeos::AUDIO_TYPE_INTERNAL_SPEAKER:
return l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_SPEAKER);
case chromeos::AUDIO_TYPE_INTERNAL_MIC:
return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_MIC);
case chromeos::AUDIO_TYPE_USB:
return l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_AUDIO_USB_DEVICE,
base::UTF8ToUTF16(device.display_name));
case chromeos::AUDIO_TYPE_BLUETOOTH:
return l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_AUDIO_BLUETOOTH_DEVICE,
base::UTF8ToUTF16(device.display_name));
case chromeos::AUDIO_TYPE_HDMI:
return l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_AUDIO_HDMI_DEVICE,
base::UTF8ToUTF16(device.display_name));
default:
return base::UTF8ToUTF16(device.display_name);
}
}
} // namespace
namespace tray {
class VolumeButton : public views::ToggleImageButton {
public:
explicit VolumeButton(views::ButtonListener* listener)
: views::ToggleImageButton(listener),
image_index_(-1) {
SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE);
image_ = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_AURA_UBER_TRAY_VOLUME_LEVELS);
SetPreferredSize(gfx::Size(kTrayPopupItemHeight, kTrayPopupItemHeight));
Update();
}
virtual ~VolumeButton() {}
void Update() {
float level = GetVolumeLevel();
int image_index = IsAudioMuted() ?
0 : (level == 1.0 ?
kVolumeLevels :
std::max(1, int(std::ceil(level * (kVolumeLevels - 1)))));
if (image_index != image_index_) {
gfx::Rect region(0, image_index * kVolumeImageHeight,
kVolumeImageWidth, kVolumeImageHeight);
gfx::ImageSkia image_skia = gfx::ImageSkiaOperations::ExtractSubset(
*(image_.ToImageSkia()), region);
SetImage(views::CustomButton::STATE_NORMAL, &image_skia);
image_index_ = image_index;
}
SchedulePaint();
}
private:
// Overridden from views::View.
virtual gfx::Size GetPreferredSize() OVERRIDE {
gfx::Size size = views::ToggleImageButton::GetPreferredSize();
size.set_height(kTrayPopupItemHeight);
return size;
}
gfx::Image image_;
int image_index_;
DISALLOW_COPY_AND_ASSIGN(VolumeButton);
};
class VolumeSlider : public views::Slider {
public:
explicit VolumeSlider(views::SliderListener* listener)
: views::Slider(listener, views::Slider::HORIZONTAL) {
set_focus_border_color(kFocusBorderColor);
SetValue(GetVolumeLevel());
SetAccessibleName(
ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
IDS_ASH_STATUS_TRAY_VOLUME));
Update();
}
virtual ~VolumeSlider() {}
void Update() {
UpdateState(!IsAudioMuted());
}
DISALLOW_COPY_AND_ASSIGN(VolumeSlider);
};
// Vertical bar separator that can be placed on the VolumeView.
class BarSeparator : public views::View {
public:
BarSeparator() {}
virtual ~BarSeparator() {}
// Overriden from views::View.
virtual gfx::Size GetPreferredSize() OVERRIDE {
return gfx::Size(kBarSeparatorWidth, kBarSeparatorHeight);
}
private:
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
canvas->FillRect(gfx::Rect(width() / 2, 0, 1, height()),
kButtonStrokeColor);
}
DISALLOW_COPY_AND_ASSIGN(BarSeparator);
};
class VolumeView : public ActionableView,
public views::ButtonListener,
public views::SliderListener {
public:
VolumeView(SystemTrayItem* owner, bool is_default_view)
: owner_(owner),
icon_(NULL),
slider_(NULL),
bar_(NULL),
device_type_(NULL),
more_(NULL),
is_default_view_(is_default_view) {
SetFocusable(false);
SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
kTrayPopupPaddingHorizontal, 0, kTrayPopupPaddingBetweenItems));
icon_ = new VolumeButton(this);
AddChildView(icon_);
slider_ = new VolumeSlider(this);
AddChildView(slider_);
bar_ = new BarSeparator;
AddChildView(bar_);
device_type_ = new views::ImageView;
AddChildView(device_type_);
more_ = new views::ImageView;
more_->EnableCanvasFlippingForRTLUI(true);
more_->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_AURA_UBER_TRAY_MORE).ToImageSkia());
AddChildView(more_);
Update();
}
virtual ~VolumeView() {}
void Update() {
icon_->Update();
slider_->Update();
UpdateDeviceTypeAndMore();
Layout();
}
// Sets volume level on slider_, |percent| is ranged from [0.00] to [1.00].
void SetVolumeLevel(float percent) {
// Slider's value is in finer granularity than audio volume level(0.01),
// there will be a small discrepancy between slider's value and volume level
// on audio side. To avoid the jittering in slider UI, do not set change
// slider value if the change is less than 1%.
if (std::abs(percent-slider_->value()) < 0.01)
return;
// The change in volume will be reflected via accessibility system events,
// so we prevent the UI event from being sent here.
slider_->set_enable_accessibility_events(false);
slider_->SetValue(percent);
// It is possible that the volume was (un)muted, but the actual volume level
// did not change. In that case, setting the value of the slider won't
// trigger an update. So explicitly trigger an update.
Update();
slider_->set_enable_accessibility_events(true);
}
private:
// Updates bar_, device_type_ icon, and more_ buttons.
void UpdateDeviceTypeAndMore() {
if (!ash::switches::ShowAudioDeviceMenu() || !is_default_view_) {
more_->SetVisible(false);
bar_->SetVisible(false);
device_type_->SetVisible(false);
return;
}
CrasAudioHandler* audio_handler = CrasAudioHandler::Get();
bool show_more = audio_handler->has_alternative_output() ||
audio_handler->has_alternative_input();
more_->SetVisible(show_more);
// Show output device icon if necessary.
chromeos::AudioDevice device;
if (!audio_handler->GetActiveOutputDevice(&device))
return;
int device_icon = GetAudioDeviceIconId(device.type);
bar_->SetVisible(show_more);
if (device_icon != kNoAudioDeviceIcon) {
device_type_->SetVisible(true);
device_type_->SetImage(
ui::ResourceBundle::GetSharedInstance().GetImageNamed(
device_icon).ToImageSkia());
} else {
device_type_->SetVisible(false);
}
}
void HandleVolumeUp(int volume) {
CrasAudioHandler* audio_handler = CrasAudioHandler::Get();
audio_handler->SetOutputVolumePercent(volume);
if (audio_handler->IsOutputMuted() &&
!audio_handler->IsOutputVolumeBelowDefaultMuteLvel())
audio_handler->SetOutputMute(false);
}
void HandleVolumeDown(int volume) {
CrasAudioHandler* audio_handler = CrasAudioHandler::Get();
audio_handler->SetOutputVolumePercent(volume);
if (audio_handler->IsOutputVolumeBelowDefaultMuteLvel() &&
!audio_handler->IsOutputMuted()) {
audio_handler->SetOutputMute(true);
} else if (!audio_handler->IsOutputVolumeBelowDefaultMuteLvel() &&
audio_handler->IsOutputMuted()) {
audio_handler->SetOutputMute(false);
}
}
// Overridden from views::View.
virtual void Layout() OVERRIDE {
views::View::Layout();
if (!more_->visible()) {
int w = width() - slider_->bounds().x() -
kSliderRightPaddingToVolumeViewEdge;
slider_->SetSize(gfx::Size(w, slider_->height()));
return;
}
// Make sure the chevron always has the full size.
gfx::Size size = more_->GetPreferredSize();
gfx::Rect bounds(size);
bounds.set_x(width() - size.width() - kTrayPopupPaddingBetweenItems);
bounds.set_y((height() - size.height()) / 2);
more_->SetBoundsRect(bounds);
// Layout either bar_ or device_type_ at the left of the more_ button.
views::View* view_left_to_more;
if (device_type_->visible())
view_left_to_more = device_type_;
else
view_left_to_more = bar_;
gfx::Size view_size = view_left_to_more->GetPreferredSize();
gfx::Rect view_bounds(view_size);
view_bounds.set_x(more_->bounds().x() - view_size.width() -
kExtraPaddingBetweenBarAndMore);
view_bounds.set_y((height() - view_size.height()) / 2);
view_left_to_more->SetBoundsRect(view_bounds);
// Layout vertical bar next to view_left_to_more if device_type_ is visible.
if (device_type_->visible()) {
gfx::Size bar_size = bar_->GetPreferredSize();
gfx::Rect bar_bounds(bar_size);
bar_bounds.set_x(view_left_to_more->bounds().x() - bar_size.width());
bar_bounds.set_y((height() - bar_size.height()) / 2);
bar_->SetBoundsRect(bar_bounds);
}
// Layout slider, calculate slider width.
gfx::Rect slider_bounds = slider_->bounds();
slider_bounds.set_width(
bar_->bounds().x()
- (device_type_->visible() ? 0 : kTrayPopupPaddingBetweenItems)
- slider_bounds.x());
slider_->SetBoundsRect(slider_bounds);
}
// Overridden from views::ButtonListener.
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE {
CHECK(sender == icon_);
bool mute_on = !IsAudioMuted();
CrasAudioHandler::Get()->SetOutputMute(mute_on);
if (!mute_on)
CrasAudioHandler::Get()->AdjustOutputVolumeToAudibleLevel();
}
// Overridden from views:SliderListener.
virtual void SliderValueChanged(views::Slider* sender,
float value,
float old_value,
views::SliderChangeReason reason) OVERRIDE {
if (reason == views::VALUE_CHANGED_BY_USER) {
int volume = value * 100.0f;
int old_volume = CrasAudioHandler::Get()->GetOutputVolumePercent();
// Do not call change audio volume if the difference is less than
// 1%, which is beyond cras audio api's granularity for output volume.
if (std::abs(volume - old_volume) < 1)
return;
Shell::GetInstance()->metrics()->RecordUserMetricsAction(
is_default_view_ ?
ash::UMA_STATUS_AREA_CHANGED_VOLUME_MENU :
ash::UMA_STATUS_AREA_CHANGED_VOLUME_POPUP);
if (volume > old_volume)
HandleVolumeUp(volume);
else
HandleVolumeDown(volume);
}
icon_->Update();
}
// Overriden from ActionableView.
virtual bool PerformAction(const ui::Event& event) OVERRIDE {
if (!more_->visible())
return false;
owner_->TransitionDetailedView();
return true;
}
SystemTrayItem* owner_;
VolumeButton* icon_;
VolumeSlider* slider_;
BarSeparator* bar_;
views::ImageView* device_type_;
views::ImageView* more_;
bool is_default_view_;
DISALLOW_COPY_AND_ASSIGN(VolumeView);
};
class AudioDetailedView : public TrayDetailsView,
public ViewClickListener {
public:
AudioDetailedView(SystemTrayItem* owner, user::LoginStatus login)
: TrayDetailsView(owner),
login_(login) {
CreateItems();
Update();
}
virtual ~AudioDetailedView() {
}
void Update() {
UpdateAudioDevices();
Layout();
}
private:
void CreateItems() {
CreateScrollableList();
CreateHeaderEntry();
}
void CreateHeaderEntry() {
CreateSpecialRow(IDS_ASH_STATUS_TRAY_AUDIO, this);
}
void UpdateAudioDevices() {
output_devices_.clear();
input_devices_.clear();
chromeos::AudioDeviceList devices;
CrasAudioHandler::Get()->GetAudioDevices(&devices);
for (size_t i = 0; i < devices.size(); ++i) {
if (devices[i].is_input)
input_devices_.push_back(devices[i]);
else
output_devices_.push_back(devices[i]);
}
UpdateScrollableList();
}
void UpdateScrollableList() {
scroll_content()->RemoveAllChildViews(true);
device_map_.clear();
// Add audio output devices.
AddScrollListInfoItem(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_OUTPUT));
for (size_t i = 0; i < output_devices_.size(); ++i) {
HoverHighlightView* container = AddScrollListItem(
GetAudioDeviceName(output_devices_[i]),
gfx::Font::NORMAL,
output_devices_[i].active); /* checkmark if active */
device_map_[container] = output_devices_[i];
}
AddScrollSeparator();
// Add audio input devices.
AddScrollListInfoItem(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_INPUT));
for (size_t i = 0; i < input_devices_.size(); ++i) {
HoverHighlightView* container = AddScrollListItem(
GetAudioDeviceName(input_devices_[i]),
gfx::Font::NORMAL,
input_devices_[i].active); /* checkmark if active */
device_map_[container] = input_devices_[i];
}
scroll_content()->SizeToPreferredSize();
scroller()->Layout();
}
void AddScrollListInfoItem(const base::string16& text) {
views::Label* label = new views::Label(
text,
ui::ResourceBundle::GetSharedInstance().GetFontList(
ui::ResourceBundle::BoldFont));
// Align info item with checkbox items
int margin = kTrayPopupPaddingHorizontal +
kTrayPopupDetailsLabelExtraLeftMargin;
int left_margin = 0;
int right_margin = 0;
if (base::i18n::IsRTL())
right_margin = margin;
else
left_margin = margin;
label->SetBorder(
views::Border::CreateEmptyBorder(ash::kTrayPopupPaddingBetweenItems,
left_margin,
ash::kTrayPopupPaddingBetweenItems,
right_margin));
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
label->SetEnabledColor(SkColorSetARGB(192, 0, 0, 0));
scroll_content()->AddChildView(label);
}
HoverHighlightView* AddScrollListItem(const base::string16& text,
gfx::Font::FontStyle style,
bool checked) {
HoverHighlightView* container = new HoverHighlightView(this);
container->AddCheckableLabel(text, style, checked);
scroll_content()->AddChildView(container);
return container;
}
// Overridden from ViewClickListener.
virtual void OnViewClicked(views::View* sender) OVERRIDE {
if (sender == footer()->content()) {
TransitionToDefaultView();
} else {
AudioDeviceMap::iterator iter = device_map_.find(sender);
if (iter == device_map_.end())
return;
chromeos::AudioDevice& device = iter->second;
CrasAudioHandler::Get()->SwitchToDevice(device);
}
}
typedef std::map<views::View*, chromeos::AudioDevice> AudioDeviceMap;
user::LoginStatus login_;
chromeos::AudioDeviceList output_devices_;
chromeos::AudioDeviceList input_devices_;
AudioDeviceMap device_map_;
DISALLOW_COPY_AND_ASSIGN(AudioDetailedView);
};
} // namespace tray
TrayAudio::TrayAudio(SystemTray* system_tray)
: TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_VOLUME_MUTE),
volume_view_(NULL),
audio_detail_(NULL),
pop_up_volume_view_(false) {
CrasAudioHandler::Get()->AddAudioObserver(this);
}
TrayAudio::~TrayAudio() {
if (CrasAudioHandler::IsInitialized())
CrasAudioHandler::Get()->RemoveAudioObserver(this);
}
bool TrayAudio::GetInitialVisibility() {
return IsAudioMuted();
}
views::View* TrayAudio::CreateDefaultView(user::LoginStatus status) {
volume_view_ = new tray::VolumeView(this, true);
return volume_view_;
}
views::View* TrayAudio::CreateDetailedView(user::LoginStatus status) {
if (!ash::switches::ShowAudioDeviceMenu() || pop_up_volume_view_) {
volume_view_ = new tray::VolumeView(this, false);
return volume_view_;
} else {
Shell::GetInstance()->metrics()->RecordUserMetricsAction(
ash::UMA_STATUS_AREA_DETAILED_AUDIO_VIEW);
audio_detail_ = new tray::AudioDetailedView(this, status);
return audio_detail_;
}
}
void TrayAudio::DestroyDefaultView() {
volume_view_ = NULL;
}
void TrayAudio::DestroyDetailedView() {
if (audio_detail_) {
audio_detail_ = NULL;
} else if (volume_view_) {
volume_view_ = NULL;
pop_up_volume_view_ = false;
}
}
bool TrayAudio::ShouldHideArrow() const {
return true;
}
bool TrayAudio::ShouldShowShelf() const {
return ash::switches::ShowAudioDeviceMenu() && !pop_up_volume_view_;
}
void TrayAudio::OnOutputVolumeChanged() {
float percent = GetVolumeLevel();
if (tray_view())
tray_view()->SetVisible(GetInitialVisibility());
if (volume_view_) {
volume_view_->SetVolumeLevel(percent);
SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds);
return;
}
pop_up_volume_view_ = true;
PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false);
}
void TrayAudio::OnOutputMuteChanged() {
if (tray_view())
tray_view()->SetVisible(GetInitialVisibility());
if (volume_view_) {
volume_view_->Update();
SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds);
} else {
pop_up_volume_view_ = true;
PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false);
}
}
void TrayAudio::OnInputGainChanged() {
}
void TrayAudio::OnInputMuteChanged() {
}
void TrayAudio::OnAudioNodesChanged() {
Update();
}
void TrayAudio::OnActiveOutputNodeChanged() {
Update();
}
void TrayAudio::OnActiveInputNodeChanged() {
Update();
}
void TrayAudio::Update() {
if (tray_view())
tray_view()->SetVisible(GetInitialVisibility());
if (audio_detail_)
audio_detail_->Update();
if (volume_view_) {
volume_view_->SetVolumeLevel(GetVolumeLevel());
volume_view_->Update();
}
}
} // namespace internal
} // namespace ash
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/chromeos/audio/tray_audio_chromeos.h"
#include "ash/ash_switches.h"
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/shell.h"
#include "ash/system/audio/volume_view.h"
#include "ash/system/chromeos/audio/audio_detailed_view.h"
#include "ui/views/view.h"
namespace ash {
namespace internal {
TrayAudioChromeOs::TrayAudioChromeOs(
SystemTray* system_tray,
system::TrayAudioDelegate* audio_delegate)
: TrayAudio(system_tray, audio_delegate),
audio_detail_view_(NULL) {
}
TrayAudioChromeOs::~TrayAudioChromeOs() {
}
void TrayAudioChromeOs::Update() {
TrayAudio::Update();
if (audio_detail_view_)
audio_detail_view_->Update();
}
views::View* TrayAudioChromeOs::CreateDetailedView(user::LoginStatus status) {
if (!ash::switches::ShowAudioDeviceMenu() || pop_up_volume_view_) {
volume_view_ = new tray::VolumeView(this, audio_delegate_, false);
return volume_view_;
} else {
Shell::GetInstance()->metrics()->RecordUserMetricsAction(
ash::UMA_STATUS_AREA_DETAILED_AUDIO_VIEW);
audio_detail_view_ =
new tray::AudioDetailedView(this, status);
return audio_detail_view_;
}
}
void TrayAudioChromeOs::DestroyDetailedView() {
if (audio_detail_view_) {
audio_detail_view_ = NULL;
} else if (volume_view_) {
volume_view_ = NULL;
pop_up_volume_view_ = false;
}
}
} // namespace internal
} // namespace ash
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_CHROMEOS_H_
#define ASH_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_CHROMEOS_H_
#include "ash/ash_export.h"
#include "ash/system/audio/tray_audio.h"
namespace ash {
namespace internal {
namespace tray {
class AudioDetailedView;
}
class ASH_EXPORT TrayAudioChromeOs : public TrayAudio {
public:
explicit TrayAudioChromeOs(SystemTray* system_tray,
system::TrayAudioDelegate* audio_delegate);
virtual ~TrayAudioChromeOs();
protected:
// Overridden from TrayAudio
virtual void Update() OVERRIDE;
private:
// Overridden from SystemTrayItem.
virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE;
virtual void DestroyDetailedView() OVERRIDE;
tray::AudioDetailedView* audio_detail_view_;
DISALLOW_COPY_AND_ASSIGN(TrayAudioChromeOs);
};
} // namespace internal
} // namespace ash
#endif // ASH_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_CHROMEOS_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/chromeos/audio/tray_audio_delegate_chromeos.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "grit/ash_resources.h"
#include "grit/ash_strings.h"
using chromeos::CrasAudioHandler;
namespace ash {
namespace system {
void TrayAudioDelegateChromeOs::AdjustOutputVolumeToAudibleLevel() {
CrasAudioHandler::Get()->AdjustOutputVolumeToAudibleLevel();
}
int TrayAudioDelegateChromeOs::GetOutputDefaultVolumeMuteLevel() {
return CrasAudioHandler::Get()->GetOutputDefaultVolumeMuteThreshold();
}
int TrayAudioDelegateChromeOs::GetOutputVolumeLevel() {
return CrasAudioHandler::Get()->GetOutputVolumePercent();
}
int TrayAudioDelegateChromeOs::GetActiveOutputDeviceIconId() {
chromeos::AudioDevice device;
if (!CrasAudioHandler::Get()->GetActiveOutputDevice(&device))
return kNoAudioDeviceIcon;
if (device.type == chromeos::AUDIO_TYPE_HEADPHONE)
return IDR_AURA_UBER_TRAY_AUDIO_HEADPHONE;
else if (device.type == chromeos::AUDIO_TYPE_USB)
return IDR_AURA_UBER_TRAY_AUDIO_USB;
else if (device.type == chromeos::AUDIO_TYPE_BLUETOOTH)
return IDR_AURA_UBER_TRAY_AUDIO_BLUETOOTH;
else if (device.type == chromeos::AUDIO_TYPE_HDMI)
return IDR_AURA_UBER_TRAY_AUDIO_HDMI;
else
return kNoAudioDeviceIcon;
}
bool TrayAudioDelegateChromeOs::HasAlternativeSources() {
CrasAudioHandler* audio_handler = CrasAudioHandler::Get();
return (audio_handler->has_alternative_output() ||
audio_handler->has_alternative_input());
}
bool TrayAudioDelegateChromeOs::IsOutputAudioMuted() {
return CrasAudioHandler::Get()->IsOutputMuted();
}
void TrayAudioDelegateChromeOs::SetOutputAudioIsMuted(bool is_muted) {
CrasAudioHandler::Get()->SetOutputMute(is_muted);
}
void TrayAudioDelegateChromeOs::SetOutputVolumeLevel(int level) {
CrasAudioHandler::Get()->SetOutputVolumePercent(level);
}
} // namespace system
} // namespace ash
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_CHROMEOS_H_
#define ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_CHROMEOS_H_
#include "ash/ash_export.h"
#include "ash/system/audio/tray_audio_delegate.h"
#include "base/compiler_specific.h"
namespace ash {
namespace system {
class ASH_EXPORT TrayAudioDelegateChromeOs : public TrayAudioDelegate {
public:
virtual ~TrayAudioDelegateChromeOs() {}
// Overridden from TrayAudioDelegate.
virtual void AdjustOutputVolumeToAudibleLevel() OVERRIDE;
virtual int GetOutputDefaultVolumeMuteLevel() OVERRIDE;
virtual int GetOutputVolumeLevel() OVERRIDE;
virtual int GetActiveOutputDeviceIconId() OVERRIDE;
virtual bool HasAlternativeSources() OVERRIDE;
virtual bool IsOutputAudioMuted() OVERRIDE;
virtual void SetOutputAudioIsMuted(bool is_muted) OVERRIDE;
virtual void SetOutputVolumeLevel(int level) OVERRIDE;
};
} // namespace system
} // namespace ash
#endif // ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_CHROMEOS_H_
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/shell/panel_window.h" #include "ash/shell/panel_window.h"
#include "ash/shell_window_ids.h" #include "ash/shell_window_ids.h"
#include "ash/system/audio/tray_audio.h"
#include "ash/system/bluetooth/tray_bluetooth.h" #include "ash/system/bluetooth/tray_bluetooth.h"
#include "ash/system/date/tray_date.h" #include "ash/system/date/tray_date.h"
#include "ash/system/drive/tray_drive.h" #include "ash/system/drive/tray_drive.h"
...@@ -47,7 +48,8 @@ ...@@ -47,7 +48,8 @@
#include "ui/views/view.h" #include "ui/views/view.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "ash/system/chromeos/audio/tray_audio.h" #include "ash/system/chromeos/audio/tray_audio_chromeos.h"
#include "ash/system/chromeos/audio/tray_audio_delegate_chromeos.h"
#include "ash/system/chromeos/brightness/tray_brightness.h" #include "ash/system/chromeos/brightness/tray_brightness.h"
#include "ash/system/chromeos/enterprise/tray_enterprise.h" #include "ash/system/chromeos/enterprise/tray_enterprise.h"
#include "ash/system/chromeos/managed/tray_locally_managed_user.h" #include "ash/system/chromeos/managed/tray_locally_managed_user.h"
...@@ -195,7 +197,9 @@ void SystemTray::CreateItems(SystemTrayDelegate* delegate) { ...@@ -195,7 +197,9 @@ void SystemTray::CreateItems(SystemTrayDelegate* delegate) {
AddTrayItem(new internal::TrayDisplay(this)); AddTrayItem(new internal::TrayDisplay(this));
AddTrayItem(new internal::ScreenCaptureTrayItem(this)); AddTrayItem(new internal::ScreenCaptureTrayItem(this));
AddTrayItem(new internal::ScreenShareTrayItem(this)); AddTrayItem(new internal::ScreenShareTrayItem(this));
AddTrayItem(new internal::TrayAudio(this)); AddTrayItem(
new internal::TrayAudioChromeOs(this,
new system::TrayAudioDelegateChromeOs()));
AddTrayItem(new internal::TrayBrightness(this)); AddTrayItem(new internal::TrayBrightness(this));
AddTrayItem(new internal::TrayCapsLock(this)); AddTrayItem(new internal::TrayCapsLock(this));
AddTrayItem(new internal::TraySettings(this)); AddTrayItem(new internal::TraySettings(this));
......
...@@ -29,6 +29,14 @@ void SystemTrayNotifier::RemoveAccessibilityObserver( ...@@ -29,6 +29,14 @@ void SystemTrayNotifier::RemoveAccessibilityObserver(
accessibility_observers_.RemoveObserver(observer); accessibility_observers_.RemoveObserver(observer);
} }
void SystemTrayNotifier::AddAudioObserver(AudioObserver* observer) {
audio_observers_.AddObserver(observer);
}
void SystemTrayNotifier::RemoveAudioObserver(AudioObserver* observer) {
audio_observers_.RemoveObserver(observer);
}
void SystemTrayNotifier::AddBluetoothObserver(BluetoothObserver* observer) { void SystemTrayNotifier::AddBluetoothObserver(BluetoothObserver* observer) {
bluetooth_observers_.AddObserver(observer); bluetooth_observers_.AddObserver(observer);
} }
...@@ -170,6 +178,41 @@ void SystemTrayNotifier::NotifyAccessibilityModeChanged( ...@@ -170,6 +178,41 @@ void SystemTrayNotifier::NotifyAccessibilityModeChanged(
OnAccessibilityModeChanged(notify)); OnAccessibilityModeChanged(notify));
} }
void SystemTrayNotifier::NotifyAudioOutputVolumeChanged() {
FOR_EACH_OBSERVER(
AudioObserver,
audio_observers_,
OnOutputVolumeChanged());
}
void SystemTrayNotifier::NotifyAudioOutputMuteChanged() {
FOR_EACH_OBSERVER(
AudioObserver,
audio_observers_,
OnOutputMuteChanged());
}
void SystemTrayNotifier::NotifyAudioNodesChanged() {
FOR_EACH_OBSERVER(
AudioObserver,
audio_observers_,
OnAudioNodesChanged());
}
void SystemTrayNotifier::NotifyAudioActiveOutputNodeChanged() {
FOR_EACH_OBSERVER(
AudioObserver,
audio_observers_,
OnActiveOutputNodeChanged());
}
void SystemTrayNotifier::NotifyAudioActiveInputNodeChanged() {
FOR_EACH_OBSERVER(
AudioObserver,
audio_observers_,
OnActiveInputNodeChanged());
}
void SystemTrayNotifier::NotifyTracingModeChanged(bool value) { void SystemTrayNotifier::NotifyTracingModeChanged(bool value) {
FOR_EACH_OBSERVER( FOR_EACH_OBSERVER(
TracingObserver, TracingObserver,
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/system/audio/audio_observer.h"
#include "ash/system/bluetooth/bluetooth_observer.h" #include "ash/system/bluetooth/bluetooth_observer.h"
#include "ash/system/chromeos/tray_tracing.h" #include "ash/system/chromeos/tray_tracing.h"
#include "ash/system/date/clock_observer.h" #include "ash/system/date/clock_observer.h"
...@@ -38,13 +39,16 @@ class NetworkStateNotifier; ...@@ -38,13 +39,16 @@ class NetworkStateNotifier;
#endif #endif
class ASH_EXPORT SystemTrayNotifier { class ASH_EXPORT SystemTrayNotifier {
public: public:
SystemTrayNotifier(); SystemTrayNotifier();
~SystemTrayNotifier(); ~SystemTrayNotifier();
void AddAccessibilityObserver(AccessibilityObserver* observer); void AddAccessibilityObserver(AccessibilityObserver* observer);
void RemoveAccessibilityObserver(AccessibilityObserver* observer); void RemoveAccessibilityObserver(AccessibilityObserver* observer);
void AddAudioObserver(AudioObserver* observer);
void RemoveAudioObserver(AudioObserver* observer);
void AddBluetoothObserver(BluetoothObserver* observer); void AddBluetoothObserver(BluetoothObserver* observer);
void RemoveBluetoothObserver(BluetoothObserver* observer); void RemoveBluetoothObserver(BluetoothObserver* observer);
...@@ -94,6 +98,11 @@ public: ...@@ -94,6 +98,11 @@ public:
void NotifyAccessibilityModeChanged( void NotifyAccessibilityModeChanged(
AccessibilityNotificationVisibility notify); AccessibilityNotificationVisibility notify);
void NotifyAudioOutputVolumeChanged();
void NotifyAudioOutputMuteChanged();
void NotifyAudioNodesChanged();
void NotifyAudioActiveOutputNodeChanged();
void NotifyAudioActiveInputNodeChanged();
void NotifyTracingModeChanged(bool value); void NotifyTracingModeChanged(bool value);
void NotifyRefreshBluetooth(); void NotifyRefreshBluetooth();
void NotifyBluetoothDiscoveringChanged(); void NotifyBluetoothDiscoveringChanged();
...@@ -131,6 +140,7 @@ public: ...@@ -131,6 +140,7 @@ public:
private: private:
ObserverList<AccessibilityObserver> accessibility_observers_; ObserverList<AccessibilityObserver> accessibility_observers_;
ObserverList<AudioObserver> audio_observers_;
ObserverList<BluetoothObserver> bluetooth_observers_; ObserverList<BluetoothObserver> bluetooth_observers_;
ObserverList<CapsLockObserver> caps_lock_observers_; ObserverList<CapsLockObserver> caps_lock_observers_;
ObserverList<ClockObserver> clock_observers_; ObserverList<ClockObserver> clock_observers_;
......
...@@ -311,6 +311,9 @@ void SystemTrayDelegateChromeOS::Initialize() { ...@@ -311,6 +311,9 @@ void SystemTrayDelegateChromeOS::Initialize() {
if (LoginState::IsInitialized()) if (LoginState::IsInitialized())
LoginState::Get()->AddObserver(this); LoginState::Get()->AddObserver(this);
if (CrasAudioHandler::IsInitialized())
CrasAudioHandler::Get()->AddAudioObserver(this);
} }
void SystemTrayDelegateChromeOS::Shutdown() { void SystemTrayDelegateChromeOS::Shutdown() {
...@@ -365,7 +368,10 @@ SystemTrayDelegateChromeOS::~SystemTrayDelegateChromeOS() { ...@@ -365,7 +368,10 @@ SystemTrayDelegateChromeOS::~SystemTrayDelegateChromeOS() {
->RemoveSessionStateObserver(this); ->RemoveSessionStateObserver(this);
LoginState::Get()->RemoveObserver(this); LoginState::Get()->RemoveObserver(this);
// Stop observing Drive operations. if (CrasAudioHandler::IsInitialized())
CrasAudioHandler::Get()->RemoveAudioObserver(this);
// Stop observing Drive operations.
UnobserveDriveUpdates(); UnobserveDriveUpdates();
policy::BrowserPolicyConnectorChromeOS* connector = policy::BrowserPolicyConnectorChromeOS* connector =
...@@ -1206,6 +1212,33 @@ void SystemTrayDelegateChromeOS::InputMethodPropertyChanged( ...@@ -1206,6 +1212,33 @@ void SystemTrayDelegateChromeOS::InputMethodPropertyChanged(
GetSystemTrayNotifier()->NotifyRefreshIME(false); GetSystemTrayNotifier()->NotifyRefreshIME(false);
} }
// Overridden from CrasAudioHandler::AudioObserver.
void SystemTrayDelegateChromeOS::OnOutputVolumeChanged() {
GetSystemTrayNotifier()->NotifyAudioOutputVolumeChanged();
}
void SystemTrayDelegateChromeOS::OnOutputMuteChanged() {
GetSystemTrayNotifier()->NotifyAudioOutputMuteChanged();
}
void SystemTrayDelegateChromeOS::OnInputGainChanged() {
}
void SystemTrayDelegateChromeOS::OnInputMuteChanged() {
}
void SystemTrayDelegateChromeOS::OnAudioNodesChanged() {
GetSystemTrayNotifier()->NotifyAudioNodesChanged();
}
void SystemTrayDelegateChromeOS::OnActiveOutputNodeChanged() {
GetSystemTrayNotifier()->NotifyAudioActiveOutputNodeChanged();
}
void SystemTrayDelegateChromeOS::OnActiveInputNodeChanged() {
GetSystemTrayNotifier()->NotifyAudioActiveInputNodeChanged();
}
// drive::JobListObserver overrides. // drive::JobListObserver overrides.
void SystemTrayDelegateChromeOS::OnJobAdded(const drive::JobInfo& job_info) { void SystemTrayDelegateChromeOS::OnJobAdded(const drive::JobInfo& job_info) {
OnJobUpdated(job_info); OnJobUpdated(job_info);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "chrome/browser/chromeos/events/system_key_event_listener.h" #include "chrome/browser/chromeos/events/system_key_event_listener.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/ash/system_tray_delegate_chromeos.h" #include "chrome/browser/ui/ash/system_tray_delegate_chromeos.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "chromeos/dbus/session_manager_client.h" #include "chromeos/dbus/session_manager_client.h"
#include "chromeos/ime/input_method_manager.h" #include "chromeos/ime/input_method_manager.h"
#include "chromeos/login/login_state.h" #include "chromeos/login/login_state.h"
...@@ -36,6 +37,7 @@ class SystemTrayDelegateChromeOS ...@@ -36,6 +37,7 @@ class SystemTrayDelegateChromeOS
public content::NotificationObserver, public content::NotificationObserver,
public input_method::InputMethodManager::Observer, public input_method::InputMethodManager::Observer,
public chromeos::LoginState::Observer, public chromeos::LoginState::Observer,
public chromeos::CrasAudioHandler::AudioObserver,
public device::BluetoothAdapter::Observer, public device::BluetoothAdapter::Observer,
public SystemKeyEventListener::CapsLockObserver, public SystemKeyEventListener::CapsLockObserver,
public policy::CloudPolicyStore::Observer, public policy::CloudPolicyStore::Observer,
...@@ -183,6 +185,15 @@ class SystemTrayDelegateChromeOS ...@@ -183,6 +185,15 @@ class SystemTrayDelegateChromeOS
virtual void InputMethodPropertyChanged( virtual void InputMethodPropertyChanged(
input_method::InputMethodManager* manager) OVERRIDE; input_method::InputMethodManager* manager) OVERRIDE;
// Overridden from CrasAudioHandler::AudioObserver.
virtual void OnOutputVolumeChanged() OVERRIDE;
virtual void OnOutputMuteChanged() OVERRIDE;
virtual void OnInputGainChanged() OVERRIDE;
virtual void OnInputMuteChanged() OVERRIDE;
virtual void OnAudioNodesChanged() OVERRIDE;
virtual void OnActiveOutputNodeChanged() OVERRIDE;
virtual void OnActiveInputNodeChanged() OVERRIDE;
// drive::JobListObserver overrides. // drive::JobListObserver overrides.
virtual void OnJobAdded(const drive::JobInfo& job_info) OVERRIDE; virtual void OnJobAdded(const drive::JobInfo& job_info) OVERRIDE;
......
...@@ -130,6 +130,10 @@ bool CrasAudioHandler::IsInputMutedForDevice(uint64 device_id) { ...@@ -130,6 +130,10 @@ bool CrasAudioHandler::IsInputMutedForDevice(uint64 device_id) {
return audio_pref_handler_->GetMuteValue(*device); return audio_pref_handler_->GetMuteValue(*device);
} }
int CrasAudioHandler::GetOutputDefaultVolumeMuteThreshold() {
return kMuteThresholdPercent;
}
int CrasAudioHandler::GetOutputVolumePercent() { int CrasAudioHandler::GetOutputVolumePercent() {
return output_volume_; return output_volume_;
} }
......
...@@ -99,6 +99,9 @@ class CHROMEOS_EXPORT CrasAudioHandler : public CrasAudioClient::Observer, ...@@ -99,6 +99,9 @@ class CHROMEOS_EXPORT CrasAudioHandler : public CrasAudioClient::Observer,
// Returns true if the output volume is below the default mute volume level. // Returns true if the output volume is below the default mute volume level.
virtual bool IsOutputVolumeBelowDefaultMuteLvel(); virtual bool IsOutputVolumeBelowDefaultMuteLvel();
// Returns volume level in 0-100% range at which the volume should be muted.
virtual int GetOutputDefaultVolumeMuteThreshold();
// Gets volume level in 0-100% range (0 being pure silence) for the current // Gets volume level in 0-100% range (0 being pure silence) for the current
// active node. // active node.
virtual int GetOutputVolumePercent(); virtual int GetOutputVolumePercent();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment