OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/system/chromeos/audio/tray_audio.h" | 5 #include "ash/system/chromeos/audio/tray_audio.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "ash/ash_constants.h" | 9 #include "ash/ash_constants.h" |
10 #include "ash/ash_switches.h" | 10 #include "ash/ash_switches.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 #include "ui/gfx/canvas.h" | 30 #include "ui/gfx/canvas.h" |
31 #include "ui/gfx/image/image.h" | 31 #include "ui/gfx/image/image.h" |
32 #include "ui/gfx/image/image_skia_operations.h" | 32 #include "ui/gfx/image/image_skia_operations.h" |
33 #include "ui/views/controls/button/image_button.h" | 33 #include "ui/views/controls/button/image_button.h" |
34 #include "ui/views/controls/image_view.h" | 34 #include "ui/views/controls/image_view.h" |
35 #include "ui/views/controls/label.h" | 35 #include "ui/views/controls/label.h" |
36 #include "ui/views/controls/slider.h" | 36 #include "ui/views/controls/slider.h" |
37 #include "ui/views/layout/box_layout.h" | 37 #include "ui/views/layout/box_layout.h" |
38 #include "ui/views/view.h" | 38 #include "ui/views/view.h" |
39 | 39 |
| 40 using chromeos::CrasAudioHandler; |
| 41 |
40 namespace ash { | 42 namespace ash { |
41 namespace internal { | 43 namespace internal { |
42 | 44 |
43 namespace { | 45 namespace { |
44 const int kVolumeImageWidth = 25; | 46 const int kVolumeImageWidth = 25; |
45 const int kVolumeImageHeight = 25; | 47 const int kVolumeImageHeight = 25; |
46 const int kBarSeparatorWidth = 25; | 48 const int kBarSeparatorWidth = 25; |
47 const int kBarSeparatorHeight = 30; | 49 const int kBarSeparatorHeight = 30; |
48 const int kSliderRightPaddingToVolumeViewEdge = 17; | 50 const int kSliderRightPaddingToVolumeViewEdge = 17; |
49 const int kExtraPaddingBetweenBarAndMore = 10; | 51 const int kExtraPaddingBetweenBarAndMore = 10; |
50 | 52 |
51 const int kNoAudioDeviceIcon = -1; | 53 const int kNoAudioDeviceIcon = -1; |
52 | 54 |
53 // IDR_AURA_UBER_TRAY_VOLUME_LEVELS contains 5 images, | 55 // IDR_AURA_UBER_TRAY_VOLUME_LEVELS contains 5 images, |
54 // The one for mute is at the 0 index and the other | 56 // The one for mute is at the 0 index and the other |
55 // four are used for ascending volume levels. | 57 // four are used for ascending volume levels. |
56 const int kVolumeLevels = 4; | 58 const int kVolumeLevels = 4; |
57 | 59 |
58 bool IsAudioMuted() { | 60 bool IsAudioMuted() { |
59 if(ash::switches::UseNewAudioHandler()) { | 61 if(ash::switches::UseNewAudioHandler()) { |
60 return chromeos::CrasAudioHandler::Get()->IsOutputMuted(); | 62 return CrasAudioHandler::Get()->IsOutputMuted(); |
61 } else { | 63 } else { |
62 return Shell::GetInstance()->system_tray_delegate()-> | 64 return Shell::GetInstance()->system_tray_delegate()-> |
63 GetVolumeControlDelegate()->IsAudioMuted(); | 65 GetVolumeControlDelegate()->IsAudioMuted(); |
64 } | 66 } |
65 } | 67 } |
66 | 68 |
67 float GetVolumeLevel() { | 69 float GetVolumeLevel() { |
68 if (ash::switches::UseNewAudioHandler()) { | 70 if (ash::switches::UseNewAudioHandler()) { |
69 return chromeos::CrasAudioHandler::Get()->GetOutputVolumePercent() / 100.0f; | 71 return CrasAudioHandler::Get()->GetOutputVolumePercent() / 100.0f; |
70 } else { | 72 } else { |
71 return Shell::GetInstance()->system_tray_delegate()-> | 73 return Shell::GetInstance()->system_tray_delegate()-> |
72 GetVolumeControlDelegate()->GetVolumeLevel(); | 74 GetVolumeControlDelegate()->GetVolumeLevel(); |
73 } | 75 } |
74 } | 76 } |
75 | 77 |
76 int GetAudioDeviceIconId(chromeos::AudioDeviceType type) { | 78 int GetAudioDeviceIconId(chromeos::AudioDeviceType type) { |
77 if (type == chromeos::AUDIO_TYPE_HEADPHONE) | 79 if (type == chromeos::AUDIO_TYPE_HEADPHONE) |
78 return IDR_AURA_UBER_TRAY_AUDIO_HEADPHONE; | 80 return IDR_AURA_UBER_TRAY_AUDIO_HEADPHONE; |
79 else if (type == chromeos::AUDIO_TYPE_USB) | 81 else if (type == chromeos::AUDIO_TYPE_USB) |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 | 215 |
214 virtual ~VolumeView() {} | 216 virtual ~VolumeView() {} |
215 | 217 |
216 void Update() { | 218 void Update() { |
217 icon_->Update(); | 219 icon_->Update(); |
218 slider_->Update(); | 220 slider_->Update(); |
219 UpdateDeviceTypeAndMore(); | 221 UpdateDeviceTypeAndMore(); |
220 Layout(); | 222 Layout(); |
221 } | 223 } |
222 | 224 |
| 225 // Sets volume level on slider_, |percent| is ranged from [0.00] to [1.00]. |
223 void SetVolumeLevel(float percent) { | 226 void SetVolumeLevel(float percent) { |
| 227 // Slider's value is in finer granularity than audio volume level(0.01), |
| 228 // there will be a small discrepancy between slider's value and volume level |
| 229 // on audio side. To avoid the jittering in slider UI, do not set change |
| 230 // slider value if the change is less than 1%. |
| 231 if (std::abs(percent-slider_->value()) < 0.01) |
| 232 return; |
224 // The change in volume will be reflected via accessibility system events, | 233 // The change in volume will be reflected via accessibility system events, |
225 // so we prevent the UI event from being sent here. | 234 // so we prevent the UI event from being sent here. |
226 slider_->set_enable_accessibility_events(false); | 235 slider_->set_enable_accessibility_events(false); |
227 slider_->SetValue(percent); | 236 slider_->SetValue(percent); |
228 // It is possible that the volume was (un)muted, but the actual volume level | 237 // It is possible that the volume was (un)muted, but the actual volume level |
229 // did not change. In that case, setting the value of the slider won't | 238 // did not change. In that case, setting the value of the slider won't |
230 // trigger an update. So explicitly trigger an update. | 239 // trigger an update. So explicitly trigger an update. |
231 Update(); | 240 Update(); |
232 slider_->set_enable_accessibility_events(true); | 241 slider_->set_enable_accessibility_events(true); |
233 } | 242 } |
234 | 243 |
235 private: | 244 private: |
236 // Updates bar_, device_type_ icon, and more_ buttons. | 245 // Updates bar_, device_type_ icon, and more_ buttons. |
237 void UpdateDeviceTypeAndMore() { | 246 void UpdateDeviceTypeAndMore() { |
238 if (!ash::switches::ShowAudioDeviceMenu() || !is_default_view_) { | 247 if (!ash::switches::ShowAudioDeviceMenu() || !is_default_view_) { |
239 more_->SetVisible(false); | 248 more_->SetVisible(false); |
240 bar_->SetVisible(false); | 249 bar_->SetVisible(false); |
241 device_type_->SetVisible(false); | 250 device_type_->SetVisible(false); |
242 return; | 251 return; |
243 } | 252 } |
244 | 253 |
245 chromeos::CrasAudioHandler* audio_handler = | 254 CrasAudioHandler* audio_handler = CrasAudioHandler::Get(); |
246 chromeos::CrasAudioHandler::Get(); | |
247 bool show_more = audio_handler->has_alternative_output() || | 255 bool show_more = audio_handler->has_alternative_output() || |
248 audio_handler->has_alternative_input(); | 256 audio_handler->has_alternative_input(); |
249 more_->SetVisible(show_more); | 257 more_->SetVisible(show_more); |
250 | 258 |
251 // Show output device icon if necessary. | 259 // Show output device icon if necessary. |
252 chromeos::AudioDevice device; | 260 chromeos::AudioDevice device; |
253 audio_handler->GetActiveOutputDevice(&device); | 261 audio_handler->GetActiveOutputDevice(&device); |
254 int device_icon = GetAudioDeviceIconId(device.type); | 262 int device_icon = GetAudioDeviceIconId(device.type); |
255 if (device_icon != kNoAudioDeviceIcon) { | 263 if (device_icon != kNoAudioDeviceIcon) { |
256 device_type_->SetVisible(true); | 264 device_type_->SetVisible(true); |
257 device_type_->SetImage( | 265 device_type_->SetImage( |
258 ui::ResourceBundle::GetSharedInstance().GetImageNamed( | 266 ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
259 device_icon).ToImageSkia()); | 267 device_icon).ToImageSkia()); |
260 bar_->SetVisible(false); | 268 bar_->SetVisible(false); |
261 } else { | 269 } else { |
262 device_type_->SetVisible(false); | 270 device_type_->SetVisible(false); |
263 bar_->SetVisible(show_more); | 271 bar_->SetVisible(show_more); |
264 } | 272 } |
265 } | 273 } |
266 | 274 |
| 275 void HandleVolumeUp(int volume) { |
| 276 CrasAudioHandler* audio_handler = CrasAudioHandler::Get(); |
| 277 audio_handler->SetOutputVolumePercent(volume); |
| 278 if (audio_handler->IsOutputMuted() && |
| 279 !audio_handler->IsOutputVolumeBelowDefaultMuteLvel()) |
| 280 audio_handler->SetOutputMute(false); |
| 281 } |
| 282 |
| 283 void HandleVolumeDown(int volume) { |
| 284 CrasAudioHandler* audio_handler = CrasAudioHandler::Get(); |
| 285 audio_handler->SetOutputVolumePercent(volume); |
| 286 if (audio_handler->IsOutputVolumeBelowDefaultMuteLvel() && |
| 287 !audio_handler->IsOutputMuted()) { |
| 288 audio_handler->SetOutputMute(true); |
| 289 } else if (!audio_handler->IsOutputVolumeBelowDefaultMuteLvel() && |
| 290 audio_handler->IsOutputMuted()) { |
| 291 audio_handler->SetOutputMute(false); |
| 292 } |
| 293 } |
| 294 |
267 // Overridden from views::View. | 295 // Overridden from views::View. |
268 virtual void Layout() OVERRIDE { | 296 virtual void Layout() OVERRIDE { |
269 views::View::Layout(); | 297 views::View::Layout(); |
270 | 298 |
271 if (!more_->visible()) { | 299 if (!more_->visible()) { |
272 int w = width() - slider_->bounds().x() - | 300 int w = width() - slider_->bounds().x() - |
273 kSliderRightPaddingToVolumeViewEdge; | 301 kSliderRightPaddingToVolumeViewEdge; |
274 slider_->SetSize(gfx::Size(w, slider_->height())); | 302 slider_->SetSize(gfx::Size(w, slider_->height())); |
275 return; | 303 return; |
276 } | 304 } |
(...skipping 25 matching lines...) Expand all Loading... |
302 view_left_to_more->bounds().x() - kTrayPopupPaddingBetweenItems | 330 view_left_to_more->bounds().x() - kTrayPopupPaddingBetweenItems |
303 - slider_bounds.x()); | 331 - slider_bounds.x()); |
304 slider_->SetBoundsRect(slider_bounds); | 332 slider_->SetBoundsRect(slider_bounds); |
305 } | 333 } |
306 | 334 |
307 // Overridden from views::ButtonListener. | 335 // Overridden from views::ButtonListener. |
308 virtual void ButtonPressed(views::Button* sender, | 336 virtual void ButtonPressed(views::Button* sender, |
309 const ui::Event& event) OVERRIDE { | 337 const ui::Event& event) OVERRIDE { |
310 CHECK(sender == icon_); | 338 CHECK(sender == icon_); |
311 if (ash::switches::UseNewAudioHandler()) { | 339 if (ash::switches::UseNewAudioHandler()) { |
312 chromeos::CrasAudioHandler::Get()->SetOutputMute(!IsAudioMuted()); | 340 bool mute_on = !IsAudioMuted(); |
| 341 CrasAudioHandler::Get()->SetOutputMute(mute_on); |
| 342 if (!mute_on) |
| 343 CrasAudioHandler::Get()->AdjustOutputVolumeToAudibleLevel(); |
313 } else { | 344 } else { |
314 ash::Shell::GetInstance()->system_tray_delegate()-> | 345 ash::Shell::GetInstance()->system_tray_delegate()-> |
315 GetVolumeControlDelegate()->SetAudioMuted(!IsAudioMuted()); | 346 GetVolumeControlDelegate()->SetAudioMuted(!IsAudioMuted()); |
316 } | 347 } |
317 } | 348 } |
318 | 349 |
319 // Overridden from views:SliderListener. | 350 // Overridden from views:SliderListener. |
320 virtual void SliderValueChanged(views::Slider* sender, | 351 virtual void SliderValueChanged(views::Slider* sender, |
321 float value, | 352 float value, |
322 float old_value, | 353 float old_value, |
323 views::SliderChangeReason reason) OVERRIDE { | 354 views::SliderChangeReason reason) OVERRIDE { |
324 if (reason == views::VALUE_CHANGED_BY_USER) { | 355 if (reason == views::VALUE_CHANGED_BY_USER) { |
325 if (ash::switches::UseNewAudioHandler()) { | 356 if (ash::switches::UseNewAudioHandler()) { |
326 chromeos::CrasAudioHandler::Get()-> | 357 int volume = value * 100.0f; |
327 SetOutputVolumePercent(value * 100.0f); | 358 int old_volume = CrasAudioHandler::Get()->GetOutputVolumePercent(); |
328 } | 359 // Do not call change audio volume if the difference is less than |
329 else { | 360 // 1%, which is beyond cras audio api's granularity for output volume. |
| 361 if (std::abs(volume - old_volume) < 1) |
| 362 return; |
| 363 if (volume > old_volume) |
| 364 HandleVolumeUp(volume); |
| 365 else |
| 366 HandleVolumeDown(volume); |
| 367 } else { |
330 ash::Shell::GetInstance()->system_tray_delegate()-> | 368 ash::Shell::GetInstance()->system_tray_delegate()-> |
331 GetVolumeControlDelegate()->SetVolumeLevel(value); | 369 GetVolumeControlDelegate()->SetVolumeLevel(value); |
332 } | 370 } |
333 } | 371 } |
334 icon_->Update(); | 372 icon_->Update(); |
335 } | 373 } |
336 | 374 |
337 // Overriden from ActinableView. | 375 // Overriden from ActinableView. |
338 virtual bool PerformAction(const ui::Event& event) OVERRIDE { | 376 virtual bool PerformAction(const ui::Event& event) OVERRIDE { |
339 if (!more_->visible()) | 377 if (!more_->visible()) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 } | 416 } |
379 | 417 |
380 void CreateHeaderEntry() { | 418 void CreateHeaderEntry() { |
381 CreateSpecialRow(IDS_ASH_STATUS_TRAY_AUDIO, this); | 419 CreateSpecialRow(IDS_ASH_STATUS_TRAY_AUDIO, this); |
382 } | 420 } |
383 | 421 |
384 void UpdateAudioDevices() { | 422 void UpdateAudioDevices() { |
385 output_devices_.clear(); | 423 output_devices_.clear(); |
386 input_devices_.clear(); | 424 input_devices_.clear(); |
387 chromeos::AudioDeviceList devices; | 425 chromeos::AudioDeviceList devices; |
388 chromeos::CrasAudioHandler::Get()->GetAudioDevices(&devices); | 426 CrasAudioHandler::Get()->GetAudioDevices(&devices); |
389 for (size_t i = 0; i < devices.size(); ++i) { | 427 for (size_t i = 0; i < devices.size(); ++i) { |
390 if (devices[i].is_input) | 428 if (devices[i].is_input) |
391 input_devices_.push_back(devices[i]); | 429 input_devices_.push_back(devices[i]); |
392 else | 430 else |
393 output_devices_.push_back(devices[i]); | 431 output_devices_.push_back(devices[i]); |
394 } | 432 } |
395 UpdateScrollableList(); | 433 UpdateScrollableList(); |
396 } | 434 } |
397 | 435 |
398 void UpdateScrollableList() { | 436 void UpdateScrollableList() { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 // Overridden from ViewClickListener. | 481 // Overridden from ViewClickListener. |
444 virtual void OnViewClicked(views::View* sender) OVERRIDE { | 482 virtual void OnViewClicked(views::View* sender) OVERRIDE { |
445 if (sender == footer()->content()) { | 483 if (sender == footer()->content()) { |
446 owner()->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING); | 484 owner()->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING); |
447 } else { | 485 } else { |
448 AudioDeviceMap::iterator iter = device_map_.find(sender); | 486 AudioDeviceMap::iterator iter = device_map_.find(sender); |
449 if (iter == device_map_.end()) | 487 if (iter == device_map_.end()) |
450 return; | 488 return; |
451 chromeos::AudioDevice& device = iter->second; | 489 chromeos::AudioDevice& device = iter->second; |
452 if (device.is_input) | 490 if (device.is_input) |
453 chromeos::CrasAudioHandler::Get()->SetActiveInputNode(device.id); | 491 CrasAudioHandler::Get()->SetActiveInputNode(device.id); |
454 else | 492 else |
455 chromeos::CrasAudioHandler::Get()->SetActiveOutputNode(device.id); | 493 CrasAudioHandler::Get()->SetActiveOutputNode(device.id); |
456 } | 494 } |
457 } | 495 } |
458 | 496 |
459 typedef std::map<views::View*, chromeos::AudioDevice> AudioDeviceMap; | 497 typedef std::map<views::View*, chromeos::AudioDevice> AudioDeviceMap; |
460 | 498 |
461 user::LoginStatus login_; | 499 user::LoginStatus login_; |
462 chromeos::AudioDeviceList output_devices_; | 500 chromeos::AudioDeviceList output_devices_; |
463 chromeos::AudioDeviceList input_devices_; | 501 chromeos::AudioDeviceList input_devices_; |
464 AudioDeviceMap device_map_; | 502 AudioDeviceMap device_map_; |
465 | 503 |
466 DISALLOW_COPY_AND_ASSIGN(AudioDetailedView); | 504 DISALLOW_COPY_AND_ASSIGN(AudioDetailedView); |
467 }; | 505 }; |
468 | 506 |
469 } // namespace tray | 507 } // namespace tray |
470 | 508 |
471 TrayAudio::TrayAudio(SystemTray* system_tray) | 509 TrayAudio::TrayAudio(SystemTray* system_tray) |
472 : TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_VOLUME_MUTE), | 510 : TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_VOLUME_MUTE), |
473 volume_view_(NULL), | 511 volume_view_(NULL), |
474 audio_detail_(NULL), | 512 audio_detail_(NULL), |
475 pop_up_volume_view_(false) { | 513 pop_up_volume_view_(false) { |
476 if (ash::switches::UseNewAudioHandler()) | 514 if (ash::switches::UseNewAudioHandler()) |
477 chromeos::CrasAudioHandler::Get()->AddAudioObserver(this); | 515 CrasAudioHandler::Get()->AddAudioObserver(this); |
478 else | 516 else |
479 Shell::GetInstance()->system_tray_notifier()->AddAudioObserver(this); | 517 Shell::GetInstance()->system_tray_notifier()->AddAudioObserver(this); |
480 } | 518 } |
481 | 519 |
482 TrayAudio::~TrayAudio() { | 520 TrayAudio::~TrayAudio() { |
483 if (ash::switches::UseNewAudioHandler()) { | 521 if (ash::switches::UseNewAudioHandler()) { |
484 if (chromeos::CrasAudioHandler::IsInitialized()) | 522 if (CrasAudioHandler::IsInitialized()) |
485 chromeos::CrasAudioHandler::Get()->RemoveAudioObserver(this); | 523 CrasAudioHandler::Get()->RemoveAudioObserver(this); |
486 } else { | 524 } else { |
487 Shell::GetInstance()->system_tray_notifier()->RemoveAudioObserver(this); | 525 Shell::GetInstance()->system_tray_notifier()->RemoveAudioObserver(this); |
488 } | 526 } |
489 } | 527 } |
490 | 528 |
491 bool TrayAudio::GetInitialVisibility() { | 529 bool TrayAudio::GetInitialVisibility() { |
492 return IsAudioMuted(); | 530 return IsAudioMuted(); |
493 } | 531 } |
494 | 532 |
495 views::View* TrayAudio::CreateDefaultView(user::LoginStatus status) { | 533 views::View* TrayAudio::CreateDefaultView(user::LoginStatus status) { |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
607 if (audio_detail_) | 645 if (audio_detail_) |
608 audio_detail_->Update(); | 646 audio_detail_->Update(); |
609 if (volume_view_) { | 647 if (volume_view_) { |
610 volume_view_->SetVolumeLevel(GetVolumeLevel()); | 648 volume_view_->SetVolumeLevel(GetVolumeLevel()); |
611 volume_view_->Update(); | 649 volume_view_->Update(); |
612 } | 650 } |
613 } | 651 } |
614 | 652 |
615 } // namespace internal | 653 } // namespace internal |
616 } // namespace ash | 654 } // namespace ash |
OLD | NEW |