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