tray_cast.cc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/system/cast/tray_cast.h"
  5. #include <map>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "ash/public/cpp/ash_view_ids.h"
  10. #include "ash/public/cpp/system_tray_client.h"
  11. #include "ash/resources/vector_icons/vector_icons.h"
  12. #include "ash/shell.h"
  13. #include "ash/strings/grit/ash_strings.h"
  14. #include "ash/system/model/system_tray_model.h"
  15. #include "ash/system/tray/hover_highlight_view.h"
  16. #include "ash/system/tray/tray_constants.h"
  17. #include "ash/system/tray/tray_detailed_view.h"
  18. #include "base/metrics/user_metrics.h"
  19. #include "base/strings/utf_string_conversions.h"
  20. #include "build/branding_buildflags.h"
  21. #include "components/access_code_cast/common/access_code_cast_metrics.h"
  22. #include "components/vector_icons/vector_icons.h"
  23. #include "ui/base/l10n/l10n_util.h"
  24. #include "ui/base/resource/resource_bundle.h"
  25. #include "ui/gfx/image/image.h"
  26. #include "ui/gfx/paint_vector_icon.h"
  27. #include "ui/gfx/vector_icon_types.h"
  28. #include "ui/views/controls/button/button.h"
  29. #include "ui/views/controls/scroll_view.h"
  30. namespace ash {
  31. namespace {
  32. // Returns the correct vector icon for |icon_type|. Some types may be different
  33. // for branded builds.
  34. const gfx::VectorIcon& SinkIconTypeToIcon(SinkIconType icon_type) {
  35. switch (icon_type) {
  36. #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
  37. case SinkIconType::kCast:
  38. return kSystemMenuCastDeviceIcon;
  39. #else
  40. case SinkIconType::kCast:
  41. return kSystemMenuCastGenericIcon;
  42. #endif
  43. case SinkIconType::kGeneric:
  44. return kSystemMenuCastGenericIcon;
  45. case SinkIconType::kCastAudioGroup:
  46. return kSystemMenuCastAudioGroupIcon;
  47. case SinkIconType::kCastAudio:
  48. return kSystemMenuCastAudioIcon;
  49. case SinkIconType::kWiredDisplay:
  50. return kSystemMenuCastGenericIcon;
  51. }
  52. NOTREACHED();
  53. return kSystemMenuCastGenericIcon;
  54. }
  55. } // namespace
  56. CastDetailedView::CastDetailedView(DetailedViewDelegate* delegate)
  57. : TrayDetailedView(delegate) {
  58. CreateItems();
  59. OnDevicesUpdated(CastConfigController::Get()->GetSinksAndRoutes());
  60. CastConfigController::Get()->AddObserver(this);
  61. }
  62. CastDetailedView::~CastDetailedView() {
  63. CastConfigController::Get()->RemoveObserver(this);
  64. }
  65. void CastDetailedView::CreateItems() {
  66. CreateScrollableList();
  67. CreateTitleRow(IDS_ASH_STATUS_TRAY_CAST);
  68. }
  69. void CastDetailedView::OnDevicesUpdated(
  70. const std::vector<SinkAndRoute>& sinks_routes) {
  71. // Add/update existing.
  72. for (const auto& device : sinks_routes)
  73. sinks_and_routes_.insert(std::make_pair(device.sink.id, device));
  74. // Remove non-existent sinks. Removing an element invalidates all existing
  75. // iterators.
  76. auto iter = sinks_and_routes_.begin();
  77. while (iter != sinks_and_routes_.end()) {
  78. bool has_receiver = false;
  79. for (auto& receiver : sinks_routes) {
  80. if (iter->first == receiver.sink.id)
  81. has_receiver = true;
  82. }
  83. if (has_receiver)
  84. ++iter;
  85. else
  86. iter = sinks_and_routes_.erase(iter);
  87. }
  88. // Update UI.
  89. UpdateReceiverListFromCachedData();
  90. Layout();
  91. }
  92. const char* CastDetailedView::GetClassName() const {
  93. return "CastDetailedView";
  94. }
  95. void CastDetailedView::UpdateReceiverListFromCachedData() {
  96. // Remove all of the existing views.
  97. view_to_sink_map_.clear();
  98. scroll_content()->RemoveAllChildViews();
  99. // Per product requirement, access code receiver should be shown before other
  100. // receivers.
  101. if (CastConfigController::Get()->AccessCodeCastingEnabled()) {
  102. add_access_code_device_ = AddScrollListItem(
  103. vector_icons::kKeyboardIcon,
  104. l10n_util::GetStringUTF16(
  105. IDS_ASH_STATUS_TRAY_CAST_ACCESS_CODE_CAST_CONNECT));
  106. }
  107. // Add a view for each receiver.
  108. for (auto& it : sinks_and_routes_) {
  109. const CastSink& sink = it.second.sink;
  110. views::View* container = AddScrollListItem(
  111. SinkIconTypeToIcon(sink.sink_icon_type), base::UTF8ToUTF16(sink.name));
  112. view_to_sink_map_[container] = sink.id;
  113. }
  114. scroll_content()->SizeToPreferredSize();
  115. scroller()->Layout();
  116. }
  117. void CastDetailedView::HandleViewClicked(views::View* view) {
  118. // Find the receiver we are going to cast to.
  119. auto it = view_to_sink_map_.find(view);
  120. if (it != view_to_sink_map_.end()) {
  121. CastConfigController::Get()->CastToSink(it->second);
  122. base::RecordAction(
  123. base::UserMetricsAction("StatusArea_Cast_Detailed_Launch_Cast"));
  124. } else if (view == add_access_code_device_) {
  125. base::RecordAction(base::UserMetricsAction(
  126. "StatusArea_Cast_Detailed_Launch_AccesCastDialog"));
  127. Shell::Get()->system_tray_model()->client()-> ShowAccessCodeCastingDialog(
  128. AccessCodeCastDialogOpenLocation::kSystemTrayCastMenu);
  129. }
  130. }
  131. } // namespace ash