1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file. 4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/audio/volume_view.h" 6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/ash_constants.h" 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/shell.h" 9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/audio/tray_audio.h" 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/audio/tray_audio_delegate.h" 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/tray/system_tray_item.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/tray/tray_constants.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "grit/ash_resources.h" 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "grit/ash_strings.h" 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/canvas.h" 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/image/image_skia_operations.h" 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/views/controls/button/image_button.h" 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/views/controls/image_view.h" 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/views/layout/box_layout.h" 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace { 23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kVolumeImageWidth = 25; 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kVolumeImageHeight = 25; 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kBarSeparatorWidth = 25; 26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kBarSeparatorHeight = 30; 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kSliderRightPaddingToVolumeViewEdge = 17; 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kExtraPaddingBetweenBarAndMore = 10; 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// IDR_AURA_UBER_TRAY_VOLUME_LEVELS contains 5 images, 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// The one for mute is at the 0 index and the other 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// four are used for ascending volume levels. 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kVolumeLevels = 4; 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace ash { 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace tray { 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class VolumeButton : public views::ToggleImageButton { 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public: 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VolumeButton(views::ButtonListener* listener, 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) system::TrayAudioDelegate* audio_delegate) 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : views::ToggleImageButton(listener), 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_(audio_delegate), 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) image_index_(-1) { 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE); 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) image_ = ui::ResourceBundle::GetSharedInstance().GetImageNamed( 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IDR_AURA_UBER_TRAY_VOLUME_LEVELS); 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Update(); 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual ~VolumeButton() {} 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void Update() { 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) float level = 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f; 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int image_index = audio_delegate_->IsOutputAudioMuted() ? 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 0 : (level == 1.0 ? 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) kVolumeLevels : 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::max(1, int(std::ceil(level * (kVolumeLevels - 1))))); 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (image_index != image_index_) { 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect region(0, image_index * kVolumeImageHeight, 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) kVolumeImageWidth, kVolumeImageHeight); 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::ImageSkia image_skia = gfx::ImageSkiaOperations::ExtractSubset( 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) *(image_.ToImageSkia()), region); 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetImage(views::CustomButton::STATE_NORMAL, &image_skia); 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) image_index_ = image_index; 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SchedulePaint(); 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private: 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Overridden from views::View. 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual gfx::Size GetPreferredSize() const OVERRIDE { 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Size size = views::ToggleImageButton::GetPreferredSize(); 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) size.set_height(kTrayPopupItemHeight); 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return size; 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) system::TrayAudioDelegate* audio_delegate_; 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Image image_; 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int image_index_; 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(VolumeButton); 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class VolumeSlider : public views::Slider { 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public: 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VolumeSlider(views::SliderListener* listener, 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) system::TrayAudioDelegate* audio_delegate) 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : views::Slider(listener, views::Slider::HORIZONTAL), 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_(audio_delegate) { 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) set_focus_border_color(kFocusBorderColor); 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetValue( 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f); 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetAccessibleName( 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ui::ResourceBundle::GetSharedInstance().GetLocalizedString( 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IDS_ASH_STATUS_TRAY_VOLUME)); 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Update(); 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual ~VolumeSlider() {} 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void Update() { 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UpdateState(!audio_delegate_->IsOutputAudioMuted()); 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private: 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) system::TrayAudioDelegate* audio_delegate_; 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(VolumeSlider); 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Vertical bar separator that can be placed on the VolumeView. 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class BarSeparator : public views::View { 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public: 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) BarSeparator() {} 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual ~BarSeparator() {} 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Overriden from views::View. 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual gfx::Size GetPreferredSize() const OVERRIDE { 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return gfx::Size(kBarSeparatorWidth, kBarSeparatorHeight); 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private: 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) canvas->FillRect(gfx::Rect(width() / 2, 0, 1, height()), 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) kButtonStrokeColor); 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(BarSeparator); 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)VolumeView::VolumeView(SystemTrayItem* owner, 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) system::TrayAudioDelegate* audio_delegate, 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool is_default_view) 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : owner_(owner), 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_(audio_delegate), 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) icon_(NULL), 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) slider_(NULL), 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bar_(NULL), 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) device_type_(NULL), 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) more_(NULL), 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) is_default_view_(is_default_view) { 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetFocusable(false); 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) kTrayPopupPaddingHorizontal, 0, kTrayPopupPaddingBetweenItems)); 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) icon_ = new VolumeButton(this, audio_delegate_); 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AddChildView(icon_); 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) slider_ = new VolumeSlider(this, audio_delegate_); 153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AddChildView(slider_); 154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bar_ = new BarSeparator; 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AddChildView(bar_); 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) device_type_ = new views::ImageView; 159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AddChildView(device_type_); 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) more_ = new views::ImageView; 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) more_->EnableCanvasFlippingForRTLUI(true); 163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) more_->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageNamed( 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IDR_AURA_UBER_TRAY_MORE).ToImageSkia()); 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AddChildView(more_); 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Update(); 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)VolumeView::~VolumeView() { 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VolumeView::Update() { 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) icon_->Update(); 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) slider_->Update(); 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UpdateDeviceTypeAndMore(); 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Layout(); 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VolumeView::SetVolumeLevel(float percent) { 181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Slider's value is in finer granularity than audio volume level(0.01), 182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // there will be a small discrepancy between slider's value and volume level 183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // on audio side. To avoid the jittering in slider UI, do not set change 184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // slider value if the change is less than 1%. 185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (std::abs(percent-slider_->value()) < 0.01) 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The change in volume will be reflected via accessibility system events, 188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // so we prevent the UI event from being sent here. 189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) slider_->set_enable_accessibility_events(false); 190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) slider_->SetValue(percent); 191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // It is possible that the volume was (un)muted, but the actual volume level 192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // did not change. In that case, setting the value of the slider won't 193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // trigger an update. So explicitly trigger an update. 194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Update(); 195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) slider_->set_enable_accessibility_events(true); 196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VolumeView::UpdateDeviceTypeAndMore() { 199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!TrayAudio::ShowAudioDeviceMenu() || !is_default_view_) { 200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) more_->SetVisible(false); 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bar_->SetVisible(false); 202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) device_type_->SetVisible(false); 203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool show_more = audio_delegate_->HasAlternativeSources(); 207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) more_->SetVisible(show_more); 208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bar_->SetVisible(show_more); 209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Show output device icon if necessary. 211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int device_icon = audio_delegate_->GetActiveOutputDeviceIconId(); 212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (device_icon != system::TrayAudioDelegate::kNoAudioDeviceIcon) { 213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) device_type_->SetVisible(true); 214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) device_type_->SetImage( 215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ui::ResourceBundle::GetSharedInstance().GetImageNamed( 216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) device_icon).ToImageSkia()); 217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) device_type_->SetVisible(false); 219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VolumeView::HandleVolumeUp(float level) { 223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_->SetOutputVolumeLevel(level); 224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (audio_delegate_->IsOutputAudioMuted() && 225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) level > audio_delegate_->GetOutputDefaultVolumeMuteLevel()) { 226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_->SetOutputAudioIsMuted(false); 227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VolumeView::HandleVolumeDown(float level) { 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_->SetOutputVolumeLevel(level); 232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!audio_delegate_->IsOutputAudioMuted() && 233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) level <= audio_delegate_->GetOutputDefaultVolumeMuteLevel()) { 234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_->SetOutputAudioIsMuted(true); 235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else if (audio_delegate_->IsOutputAudioMuted() && 236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) level > audio_delegate_->GetOutputDefaultVolumeMuteLevel()) { 237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_->SetOutputAudioIsMuted(false); 238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VolumeView::Layout() { 242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) views::View::Layout(); 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!more_->visible()) { 245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int w = width() - slider_->bounds().x() - 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) kSliderRightPaddingToVolumeViewEdge; 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) slider_->SetSize(gfx::Size(w, slider_->height())); 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Make sure the chevron always has the full size. 252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Size size = more_->GetPreferredSize(); 253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect bounds(size); 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bounds.set_x(width() - size.width() - kTrayPopupPaddingBetweenItems); 255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bounds.set_y((height() - size.height()) / 2); 256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) more_->SetBoundsRect(bounds); 257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Layout either bar_ or device_type_ at the left of the more_ button. 259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) views::View* view_left_to_more; 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (device_type_->visible()) 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) view_left_to_more = device_type_; 262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else 263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) view_left_to_more = bar_; 264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Size view_size = view_left_to_more->GetPreferredSize(); 265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect view_bounds(view_size); 266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) view_bounds.set_x(more_->bounds().x() - view_size.width() - 267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) kExtraPaddingBetweenBarAndMore); 268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) view_bounds.set_y((height() - view_size.height()) / 2); 269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) view_left_to_more->SetBoundsRect(view_bounds); 270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Layout vertical bar next to view_left_to_more if device_type_ is visible. 272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (device_type_->visible()) { 273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Size bar_size = bar_->GetPreferredSize(); 274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect bar_bounds(bar_size); 275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bar_bounds.set_x(view_left_to_more->bounds().x() - bar_size.width()); 276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bar_bounds.set_y((height() - bar_size.height()) / 2); 277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bar_->SetBoundsRect(bar_bounds); 278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Layout slider, calculate slider width. 281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect slider_bounds = slider_->bounds(); 282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) slider_bounds.set_width( 283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bar_->bounds().x() 284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) - (device_type_->visible() ? 0 : kTrayPopupPaddingBetweenItems) 285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) - slider_bounds.x()); 286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) slider_->SetBoundsRect(slider_bounds); 287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VolumeView::ButtonPressed(views::Button* sender, const ui::Event& event) { 290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CHECK(sender == icon_); 291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool mute_on = !audio_delegate_->IsOutputAudioMuted(); 292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_->SetOutputAudioIsMuted(mute_on); 293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!mute_on) 294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) audio_delegate_->AdjustOutputVolumeToAudibleLevel(); 295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) icon_->Update(); 296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void VolumeView::SliderValueChanged(views::Slider* sender, 299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) float value, 300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) float old_value, 301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) views::SliderChangeReason reason) { 302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (reason == views::VALUE_CHANGED_BY_USER) { 303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) float new_volume = value * 100.0f; 304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) float current_volume = audio_delegate_->GetOutputVolumeLevel(); 305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Do not call change audio volume if the difference is less than 306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // 1%, which is beyond cras audio api's granularity for output volume. 307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (std::abs(new_volume - current_volume) < 1.0f) 308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Shell::GetInstance()->metrics()->RecordUserMetricsAction( 310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) is_default_view_ ? 311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ash::UMA_STATUS_AREA_CHANGED_VOLUME_MENU : 312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ash::UMA_STATUS_AREA_CHANGED_VOLUME_POPUP); 313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (new_volume > current_volume) 314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HandleVolumeUp(new_volume); 315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else 316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HandleVolumeDown(new_volume); 317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) icon_->Update(); 319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool VolumeView::PerformAction(const ui::Event& event) { 322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!more_->visible()) 323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) owner_->TransitionDetailedView(); 325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return true; 326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace tray 329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace ash 330