network_feature_pod_controller.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. // Copyright 2021 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/network/network_feature_pod_controller.h"
  5. #include <memory>
  6. #include "ash/constants/ash_features.h"
  7. #include "ash/resources/vector_icons/vector_icons.h"
  8. #include "ash/session/session_controller_impl.h"
  9. #include "ash/shell.h"
  10. #include "ash/strings/grit/ash_strings.h"
  11. #include "ash/system/model/system_tray_model.h"
  12. #include "ash/system/network/active_network_icon.h"
  13. #include "ash/system/network/network_icon.h"
  14. #include "ash/system/network/network_icon_animation.h"
  15. #include "ash/system/network/tray_network_state_model.h"
  16. #include "ash/system/tray/system_tray_notifier.h"
  17. #include "ash/system/unified/unified_system_tray_controller.h"
  18. #include "base/check.h"
  19. #include "base/notreached.h"
  20. #include "base/strings/utf_string_conversions.h"
  21. #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
  22. #include "components/onc/onc_constants.h"
  23. #include "third_party/cros_system_api/dbus/service_constants.h"
  24. #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
  25. #include "ui/base/l10n/l10n_util.h"
  26. using chromeos::network_config::mojom::ActivationStateType;
  27. using chromeos::network_config::mojom::CellularStateProperties;
  28. using chromeos::network_config::mojom::ConnectionStateType;
  29. using chromeos::network_config::mojom::DeviceStateType;
  30. using chromeos::network_config::mojom::NetworkStateProperties;
  31. using chromeos::network_config::mojom::NetworkType;
  32. namespace ash {
  33. namespace {
  34. std::u16string GetSubLabelForConnectedNetwork(
  35. const NetworkStateProperties* network) {
  36. DCHECK(network &&
  37. chromeos::network_config::StateIsConnected(network->connection_state));
  38. if (!chromeos::network_config::NetworkStateMatchesType(
  39. network, NetworkType::kWireless)) {
  40. return l10n_util::GetStringUTF16(
  41. IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
  42. }
  43. if (network->type == NetworkType::kCellular) {
  44. CellularStateProperties* cellular =
  45. network->type_state->get_cellular().get();
  46. if (cellular->network_technology == onc::cellular::kTechnologyCdma1Xrtt) {
  47. return l10n_util::GetStringUTF16(
  48. IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_ONE_X);
  49. }
  50. if (cellular->network_technology == onc::cellular::kTechnologyGsm) {
  51. return l10n_util::GetStringUTF16(
  52. IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_GSM);
  53. }
  54. if (cellular->network_technology == onc::cellular::kTechnologyGprs) {
  55. return l10n_util::GetStringUTF16(
  56. IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_GPRS);
  57. }
  58. if (cellular->network_technology == onc::cellular::kTechnologyEdge) {
  59. return l10n_util::GetStringUTF16(
  60. IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_EDGE);
  61. }
  62. if (cellular->network_technology == onc::cellular::kTechnologyEvdo ||
  63. cellular->network_technology == onc::cellular::kTechnologyUmts) {
  64. return l10n_util::GetStringUTF16(
  65. IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_THREE_G);
  66. }
  67. if (cellular->network_technology == onc::cellular::kTechnologyHspa) {
  68. return l10n_util::GetStringUTF16(
  69. IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_HSPA);
  70. }
  71. if (cellular->network_technology == onc::cellular::kTechnologyHspaPlus) {
  72. return l10n_util::GetStringUTF16(
  73. IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_HSPA_PLUS);
  74. }
  75. if (cellular->network_technology == onc::cellular::kTechnologyLte) {
  76. return l10n_util::GetStringUTF16(
  77. IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_LTE);
  78. }
  79. if (cellular->network_technology == onc::cellular::kTechnologyLteAdvanced) {
  80. return l10n_util::GetStringUTF16(
  81. IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_LTE_PLUS);
  82. }
  83. // All connectivity types exposed by Shill should be covered above. However,
  84. // as a fail-safe, return the default "Connected" string here to protect
  85. // against Shill providing an unexpected value.
  86. NOTREACHED();
  87. return l10n_util::GetStringUTF16(
  88. IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
  89. }
  90. int signal_strength =
  91. chromeos::network_config::GetWirelessSignalStrength(network);
  92. switch (network_icon::GetSignalStrength(signal_strength)) {
  93. case network_icon::SignalStrength::NONE:
  94. return l10n_util::GetStringUTF16(
  95. IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
  96. case network_icon::SignalStrength::WEAK:
  97. return l10n_util::GetStringUTF16(
  98. IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_WEAK_SUBLABEL);
  99. case network_icon::SignalStrength::MEDIUM:
  100. return l10n_util::GetStringUTF16(
  101. IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_MEDIUM_SUBLABEL);
  102. case network_icon::SignalStrength::STRONG:
  103. return l10n_util::GetStringUTF16(
  104. IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_STRONG_SUBLABEL);
  105. }
  106. NOTREACHED();
  107. return l10n_util::GetStringUTF16(
  108. IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
  109. }
  110. // Returns |true| if the network type can be toggled to state |enabled|.
  111. bool NetworkTypeCanBeToggled(const NetworkStateProperties* network,
  112. bool enabled) {
  113. // The default behavior is to change the enabled state of WiFi.
  114. if (!network || network->type == NetworkType::kWiFi)
  115. return true;
  116. // Cellular and tether networks can only be disabled from clicking the feature
  117. // pod toggle, not enabled.
  118. if (!enabled && (network->type == NetworkType::kCellular ||
  119. network->type == NetworkType::kTether)) {
  120. return true;
  121. }
  122. return false;
  123. }
  124. // Returns |true| if the network type is actually toggled.
  125. bool SetNetworkTypeEnabled(bool enabled) {
  126. TrayNetworkStateModel* model =
  127. Shell::Get()->system_tray_model()->network_state_model();
  128. const NetworkStateProperties* default_network = model->default_network();
  129. if (!NetworkTypeCanBeToggled(default_network, enabled))
  130. return false;
  131. model->SetNetworkTypeEnabledState(
  132. default_network ? default_network->type : NetworkType::kWiFi, enabled);
  133. return true;
  134. }
  135. } // namespace
  136. NetworkFeaturePodController::NetworkFeaturePodController(
  137. UnifiedSystemTrayController* tray_controller)
  138. : tray_controller_(tray_controller) {
  139. DCHECK(ash::features::IsQuickSettingsNetworkRevampEnabled());
  140. Shell::Get()->system_tray_model()->network_state_model()->AddObserver(this);
  141. }
  142. NetworkFeaturePodController::~NetworkFeaturePodController() {
  143. network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
  144. Shell::Get()->system_tray_model()->network_state_model()->RemoveObserver(
  145. this);
  146. }
  147. void NetworkFeaturePodController::NetworkIconChanged() {
  148. UpdateButtonStateIfExists();
  149. }
  150. FeaturePodButton* NetworkFeaturePodController::CreateButton() {
  151. DCHECK(!button_);
  152. std::unique_ptr<NetworkFeaturePodButton> button =
  153. std::make_unique<NetworkFeaturePodButton>(/*controller=*/this,
  154. /*delegate=*/this);
  155. button_ = button.get();
  156. button_->ShowDetailedViewArrow();
  157. UpdateButtonStateIfExists();
  158. return button.release();
  159. }
  160. void NetworkFeaturePodController::OnIconPressed() {
  161. bool was_enabled = button_->IsToggled();
  162. bool can_toggle = SetNetworkTypeEnabled(!was_enabled);
  163. // The detailed view should be shown when we enable a network technology as
  164. // well as when the network technology cannot be toggled, e.g. ethernet.
  165. if (!was_enabled || !can_toggle)
  166. tray_controller_->ShowNetworkDetailedView(/*force=*/!can_toggle);
  167. }
  168. void NetworkFeaturePodController::OnLabelPressed() {
  169. SetNetworkTypeEnabled(true);
  170. tray_controller_->ShowNetworkDetailedView(/*force=*/true);
  171. }
  172. SystemTrayItemUmaType NetworkFeaturePodController::GetUmaType() const {
  173. return SystemTrayItemUmaType::UMA_NETWORK;
  174. }
  175. void NetworkFeaturePodController::OnFeaturePodButtonThemeChanged() {
  176. // All of the network icons will need to be redrawn.
  177. Shell::Get()
  178. ->system_tray_model()
  179. ->active_network_icon()
  180. ->PurgeNetworkIconCache();
  181. UpdateButtonStateIfExists();
  182. }
  183. void NetworkFeaturePodController::ActiveNetworkStateChanged() {
  184. UpdateButtonStateIfExists();
  185. }
  186. void NetworkFeaturePodController::UpdateButtonStateIfExists() {
  187. // Check |button_| here so that calling functions don't need to.
  188. if (!button_)
  189. return;
  190. TrayNetworkStateModel* model =
  191. Shell::Get()->system_tray_model()->network_state_model();
  192. const chromeos::network_config::mojom::NetworkStateProperties*
  193. default_network = model->default_network();
  194. const bool toggled =
  195. default_network ||
  196. model->GetDeviceState(NetworkType::kWiFi) == DeviceStateType::kEnabled;
  197. const network_icon::IconType icon_type =
  198. toggled ? network_icon::ICON_TYPE_FEATURE_POD_TOGGLED
  199. : network_icon::ICON_TYPE_FEATURE_POD;
  200. button_->SetToggled(toggled);
  201. bool image_animating = false;
  202. ActiveNetworkIcon* active_network_icon =
  203. Shell::Get()->system_tray_model()->active_network_icon();
  204. button_->icon_button()->SetImage(
  205. views::Button::STATE_NORMAL,
  206. active_network_icon->GetImage(ActiveNetworkIcon::Type::kSingle, icon_type,
  207. &image_animating));
  208. button_->icon_button()->SetImage(
  209. views::Button::STATE_DISABLED,
  210. active_network_icon->GetImage(
  211. ActiveNetworkIcon::Type::kSingle,
  212. network_icon::ICON_TYPE_FEATURE_POD_DISABLED, &image_animating));
  213. if (image_animating) {
  214. network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this);
  215. } else {
  216. network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
  217. }
  218. // Modifying network state is not allowed when the screen is locked.
  219. button_->SetEnabled(!Shell::Get()->session_controller()->IsScreenLocked());
  220. std::u16string tooltip;
  221. Shell::Get()
  222. ->system_tray_model()
  223. ->active_network_icon()
  224. ->GetConnectionStatusStrings(ActiveNetworkIcon::Type::kSingle,
  225. /*a11y_name=*/nullptr,
  226. /*a11y_desc=*/nullptr, &tooltip);
  227. button_->SetLabel(ComputeButtonLabel(default_network));
  228. button_->SetSubLabel(ComputeButtonSubLabel(default_network));
  229. if (!button_->GetEnabled()) {
  230. button_->SetIconAndLabelTooltips(tooltip);
  231. return;
  232. }
  233. // Make sure the tooltip only indicates the network type will be toggled by
  234. // pressing the icon only when it can be toggled (e.g. not ethernet).
  235. if (!NetworkTypeCanBeToggled(default_network, !toggled)) {
  236. button_->SetIconAndLabelTooltips(l10n_util::GetStringFUTF16(
  237. IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP, tooltip));
  238. return;
  239. }
  240. button_->SetIconTooltip(l10n_util::GetStringFUTF16(
  241. IDS_ASH_STATUS_TRAY_NETWORK_TOGGLE_TOOLTIP, tooltip));
  242. // Make sure the tooltip indicates the network type will be toggled by
  243. // pressing the label if the network type is disabled.
  244. button_->SetLabelTooltip(l10n_util::GetStringFUTF16(
  245. toggled ? IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP
  246. : IDS_ASH_STATUS_TRAY_NETWORK_TOGGLE_TOOLTIP,
  247. tooltip));
  248. }
  249. std::u16string NetworkFeaturePodController::ComputeButtonLabel(
  250. const chromeos::network_config::mojom::NetworkStateProperties* network)
  251. const {
  252. if (!network) {
  253. return l10n_util::GetStringUTF16(
  254. IDS_ASH_STATUS_TRAY_NETWORK_DISCONNECTED_LABEL);
  255. }
  256. return network->type == NetworkType::kEthernet
  257. ? l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET)
  258. : base::UTF8ToUTF16(network->name);
  259. }
  260. std::u16string NetworkFeaturePodController::ComputeButtonSubLabel(
  261. const chromeos::network_config::mojom::NetworkStateProperties* network)
  262. const {
  263. if (!network ||
  264. network->connection_state == ConnectionStateType::kNotConnected) {
  265. return l10n_util::GetStringUTF16(
  266. IDS_ASH_STATUS_TRAY_NETWORK_DISCONNECTED_SUBLABEL);
  267. }
  268. // Check whether the network is currently activating first since activating
  269. // networks are still considered connected.
  270. if (network->type == NetworkType::kCellular &&
  271. network->type_state->get_cellular()->activation_state ==
  272. ActivationStateType::kActivating) {
  273. return l10n_util::GetStringUTF16(
  274. IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING_SUBLABEL);
  275. }
  276. if (chromeos::network_config::StateIsConnected(network->connection_state)) {
  277. return GetSubLabelForConnectedNetwork(network);
  278. }
  279. DCHECK(network->connection_state == ConnectionStateType::kConnecting);
  280. return l10n_util::GetStringUTF16(
  281. IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING_SUBLABEL);
  282. }
  283. } // namespace ash