diff options
author | earthdok@chromium.org <earthdok@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-19 08:38:48 +0000 |
---|---|---|
committer | earthdok@chromium.org <earthdok@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-19 08:38:48 +0000 |
commit | bb4167536d5310f10effb7fa0d3700c6957f1787 (patch) | |
tree | 9334775d2121260487f42a9d906d236dc21042ad /ash/system/chromeos | |
parent | 69d7a49c29abea1f2d1c6ec71551e9b049843e55 (diff) | |
download | chromium_src-bb4167536d5310f10effb7fa0d3700c6957f1787.zip chromium_src-bb4167536d5310f10effb7fa0d3700c6957f1787.tar.gz chromium_src-bb4167536d5310f10effb7fa0d3700c6957f1787.tar.bz2 |
Revert 251959 "Refactor the TrayAudio code so that it can be use..."
Reverted due to memory leaks:
http://build.chromium.org/p/chromium.memory/builders/Linux%20Chromium%20OS%20ASAN%20Tests%20%281%29/builds/15922
> 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
TBR=zturner@chromium.org
Review URL: https://codereview.chromium.org/170843009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@252009 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/system/chromeos')
-rw-r--r-- | ash/system/chromeos/audio/audio_detailed_view.cc | 177 | ||||
-rw-r--r-- | ash/system/chromeos/audio/audio_detailed_view.h | 66 | ||||
-rw-r--r-- | ash/system/chromeos/audio/tray_audio.cc | 663 | ||||
-rw-r--r-- | ash/system/chromeos/audio/tray_audio.h | 61 | ||||
-rw-r--r-- | ash/system/chromeos/audio/tray_audio_chromeos.cc | 57 | ||||
-rw-r--r-- | ash/system/chromeos/audio/tray_audio_chromeos.h | 42 | ||||
-rw-r--r-- | ash/system/chromeos/audio/tray_audio_delegate_chromeos.cc | 65 | ||||
-rw-r--r-- | ash/system/chromeos/audio/tray_audio_delegate_chromeos.h | 33 |
8 files changed, 724 insertions, 440 deletions
diff --git a/ash/system/chromeos/audio/audio_detailed_view.cc b/ash/system/chromeos/audio/audio_detailed_view.cc deleted file mode 100644 index 803f4dd..0000000 --- a/ash/system/chromeos/audio/audio_detailed_view.cc +++ /dev/null @@ -1,177 +0,0 @@ -// 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 diff --git a/ash/system/chromeos/audio/audio_detailed_view.h b/ash/system/chromeos/audio/audio_detailed_view.h deleted file mode 100644 index 6953676..0000000 --- a/ash/system/chromeos/audio/audio_detailed_view.h +++ /dev/null @@ -1,66 +0,0 @@ -// 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_ diff --git a/ash/system/chromeos/audio/tray_audio.cc b/ash/system/chromeos/audio/tray_audio.cc new file mode 100644 index 0000000..c1721f6 --- /dev/null +++ b/ash/system/chromeos/audio/tray_audio.cc @@ -0,0 +1,663 @@ +// 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 diff --git a/ash/system/chromeos/audio/tray_audio.h b/ash/system/chromeos/audio/tray_audio.h new file mode 100644 index 0000000..eb6e117a --- /dev/null +++ b/ash/system/chromeos/audio/tray_audio.h @@ -0,0 +1,61 @@ +// 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. + +#ifndef ASH_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_H_ +#define ASH_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_H_ + +#include "ash/system/tray/tray_image_item.h" +#include "chromeos/audio/cras_audio_handler.h" + +namespace ash { +namespace internal { + +namespace tray { +class VolumeView; +class AudioDetailedView; +} + +class TrayAudio : public TrayImageItem, + public chromeos::CrasAudioHandler::AudioObserver { + public: + explicit TrayAudio(SystemTray* system_tray); + virtual ~TrayAudio(); + + private: + // Overridden from TrayImageItem. + virtual bool GetInitialVisibility() OVERRIDE; + + // Overridden from SystemTrayItem. + virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE; + virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE; + virtual void DestroyDefaultView() OVERRIDE; + virtual void DestroyDetailedView() OVERRIDE; + virtual bool ShouldHideArrow() const OVERRIDE; + virtual bool ShouldShowShelf() const OVERRIDE; + + // Overridden from chromeos::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; + + 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); +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_H_ diff --git a/ash/system/chromeos/audio/tray_audio_chromeos.cc b/ash/system/chromeos/audio/tray_audio_chromeos.cc deleted file mode 100644 index d15eb79..0000000 --- a/ash/system/chromeos/audio/tray_audio_chromeos.cc +++ /dev/null @@ -1,57 +0,0 @@ -// 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 diff --git a/ash/system/chromeos/audio/tray_audio_chromeos.h b/ash/system/chromeos/audio/tray_audio_chromeos.h deleted file mode 100644 index 2235842..0000000 --- a/ash/system/chromeos/audio/tray_audio_chromeos.h +++ /dev/null @@ -1,42 +0,0 @@ -// 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_ diff --git a/ash/system/chromeos/audio/tray_audio_delegate_chromeos.cc b/ash/system/chromeos/audio/tray_audio_delegate_chromeos.cc deleted file mode 100644 index 59f6ecf..0000000 --- a/ash/system/chromeos/audio/tray_audio_delegate_chromeos.cc +++ /dev/null @@ -1,65 +0,0 @@ -// 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 diff --git a/ash/system/chromeos/audio/tray_audio_delegate_chromeos.h b/ash/system/chromeos/audio/tray_audio_delegate_chromeos.h deleted file mode 100644 index 58e714d..0000000 --- a/ash/system/chromeos/audio/tray_audio_delegate_chromeos.h +++ /dev/null @@ -1,33 +0,0 @@ -// 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_ |