active_network_icon.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // Copyright 2019 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/active_network_icon.h"
  5. #include "ash/public/cpp/network_config_service.h"
  6. #include "ash/resources/vector_icons/vector_icons.h"
  7. #include "ash/shell.h"
  8. #include "ash/strings/grit/ash_strings.h"
  9. #include "ash/system/model/system_tray_model.h"
  10. #include "ash/system/network/network_icon.h"
  11. #include "ash/system/network/tray_network_state_model.h"
  12. #include "ash/system/tray/tray_constants.h"
  13. #include "base/bind.h"
  14. #include "base/strings/utf_string_conversions.h"
  15. #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
  16. #include "ui/base/l10n/l10n_util.h"
  17. #include "ui/gfx/paint_vector_icon.h"
  18. using chromeos::network_config::mojom::ActivationStateType;
  19. using chromeos::network_config::mojom::ConnectionStateType;
  20. using chromeos::network_config::mojom::DeviceStateProperties;
  21. using chromeos::network_config::mojom::DeviceStateType;
  22. using chromeos::network_config::mojom::FilterType;
  23. using chromeos::network_config::mojom::NetworkFilter;
  24. using chromeos::network_config::mojom::NetworkStateProperties;
  25. using chromeos::network_config::mojom::NetworkStatePropertiesPtr;
  26. using chromeos::network_config::mojom::NetworkType;
  27. namespace ash {
  28. namespace {
  29. const int kPurgeDelayMs = 500;
  30. bool IsTrayIcon(network_icon::IconType icon_type) {
  31. return icon_type == network_icon::ICON_TYPE_TRAY_REGULAR ||
  32. icon_type == network_icon::ICON_TYPE_TRAY_OOBE;
  33. }
  34. } // namespace
  35. ActiveNetworkIcon::ActiveNetworkIcon(TrayNetworkStateModel* model)
  36. : model_(model) {
  37. model_->AddObserver(this);
  38. }
  39. ActiveNetworkIcon::~ActiveNetworkIcon() {
  40. model_->RemoveObserver(this);
  41. }
  42. void ActiveNetworkIcon::GetConnectionStatusStrings(Type type,
  43. std::u16string* a11y_name,
  44. std::u16string* a11y_desc,
  45. std::u16string* tooltip) {
  46. const NetworkStateProperties* network = nullptr;
  47. switch (type) {
  48. case Type::kSingle:
  49. network = model_->default_network();
  50. break;
  51. case Type::kPrimary:
  52. // TODO(902409): Provide strings for technology or connecting.
  53. network = model_->default_network();
  54. break;
  55. case Type::kCellular:
  56. network = model_->active_cellular();
  57. break;
  58. }
  59. std::u16string network_name;
  60. if (network) {
  61. network_name = network->type == NetworkType::kEthernet
  62. ? l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET)
  63. : base::UTF8ToUTF16(network->name);
  64. }
  65. // Check for Activating first since activating networks may be connected.
  66. if (network && network->type == NetworkType::kCellular &&
  67. network->type_state->get_cellular()->activation_state ==
  68. ActivationStateType::kActivating) {
  69. std::u16string activating_string = l10n_util::GetStringFUTF16(
  70. IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING, network_name);
  71. if (a11y_name)
  72. *a11y_name = activating_string;
  73. if (a11y_desc)
  74. *a11y_desc = std::u16string();
  75. if (tooltip)
  76. *tooltip = activating_string;
  77. } else if (network && chromeos::network_config::StateIsConnected(
  78. network->connection_state)) {
  79. std::u16string connected_string = l10n_util::GetStringFUTF16(
  80. IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, network_name);
  81. std::u16string signal_strength_string;
  82. if (chromeos::network_config::NetworkTypeMatchesType(
  83. network->type, NetworkType::kWireless)) {
  84. // Retrieve the string describing the signal strength, if it is applicable
  85. // to |network|.
  86. int signal_strength =
  87. chromeos::network_config::GetWirelessSignalStrength(network);
  88. switch (network_icon::GetSignalStrength(signal_strength)) {
  89. case network_icon::SignalStrength::NONE:
  90. break;
  91. case network_icon::SignalStrength::WEAK:
  92. signal_strength_string = l10n_util::GetStringUTF16(
  93. IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_WEAK);
  94. break;
  95. case network_icon::SignalStrength::MEDIUM:
  96. signal_strength_string = l10n_util::GetStringUTF16(
  97. IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_MEDIUM);
  98. break;
  99. case network_icon::SignalStrength::STRONG:
  100. signal_strength_string = l10n_util::GetStringUTF16(
  101. IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_STRONG);
  102. break;
  103. }
  104. }
  105. if (a11y_name)
  106. *a11y_name = connected_string;
  107. if (a11y_desc)
  108. *a11y_desc = signal_strength_string;
  109. if (tooltip) {
  110. *tooltip = signal_strength_string.empty()
  111. ? connected_string
  112. : l10n_util::GetStringFUTF16(
  113. IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED_TOOLTIP,
  114. network_name, signal_strength_string);
  115. }
  116. } else if (network &&
  117. network->connection_state == ConnectionStateType::kConnecting) {
  118. std::u16string connecting_string = l10n_util::GetStringFUTF16(
  119. IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING, network_name);
  120. if (a11y_name)
  121. *a11y_name = connecting_string;
  122. if (a11y_desc)
  123. *a11y_desc = std::u16string();
  124. if (tooltip)
  125. *tooltip = connecting_string;
  126. } else {
  127. if (a11y_name) {
  128. *a11y_name = l10n_util::GetStringUTF16(
  129. IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED_A11Y);
  130. }
  131. if (a11y_desc)
  132. *a11y_desc = std::u16string();
  133. if (tooltip) {
  134. *tooltip = l10n_util::GetStringUTF16(
  135. IDS_ASH_STATUS_TRAY_NETWORK_DISCONNECTED_TOOLTIP);
  136. }
  137. }
  138. }
  139. gfx::ImageSkia ActiveNetworkIcon::GetImage(Type type,
  140. network_icon::IconType icon_type,
  141. bool* animating) {
  142. switch (type) {
  143. case Type::kSingle:
  144. return GetSingleImage(icon_type, animating);
  145. case Type::kPrimary:
  146. return GetDualImagePrimary(icon_type, animating);
  147. case Type::kCellular:
  148. return GetDualImageCellular(icon_type, animating);
  149. }
  150. NOTREACHED();
  151. return gfx::ImageSkia();
  152. }
  153. gfx::ImageSkia ActiveNetworkIcon::GetSingleImage(
  154. network_icon::IconType icon_type,
  155. bool* animating) {
  156. // If no network, check for cellular initializing.
  157. const NetworkStateProperties* default_network = model_->default_network();
  158. if (!default_network && cellular_uninitialized_msg_ != 0) {
  159. if (animating)
  160. *animating = true;
  161. return network_icon::GetConnectingImageForNetworkType(
  162. NetworkType::kCellular, icon_type);
  163. }
  164. return GetDefaultImageImpl(default_network, icon_type, animating);
  165. }
  166. gfx::ImageSkia ActiveNetworkIcon::GetDualImagePrimary(
  167. network_icon::IconType icon_type,
  168. bool* animating) {
  169. const NetworkStateProperties* default_network = model_->default_network();
  170. if (default_network && default_network->type == NetworkType::kCellular) {
  171. if (chromeos::network_config::StateIsConnected(
  172. default_network->connection_state)) {
  173. // TODO(902409): Show proper technology badges.
  174. if (animating)
  175. *animating = false;
  176. return gfx::CreateVectorIcon(
  177. kNetworkBadgeTechnologyLteIcon,
  178. network_icon::GetDefaultColorForIconType(icon_type));
  179. }
  180. // If Cellular is connecting, use the active non cellular network.
  181. return GetDefaultImageImpl(model_->active_non_cellular(), icon_type,
  182. animating);
  183. }
  184. return GetDefaultImageImpl(default_network, icon_type, animating);
  185. }
  186. gfx::ImageSkia ActiveNetworkIcon::GetDualImageCellular(
  187. network_icon::IconType icon_type,
  188. bool* animating) {
  189. if (model_->GetDeviceState(NetworkType::kCellular) ==
  190. DeviceStateType::kUnavailable) {
  191. if (animating)
  192. *animating = false;
  193. return gfx::ImageSkia();
  194. }
  195. if (cellular_uninitialized_msg_ != 0) {
  196. if (animating)
  197. *animating = true;
  198. return network_icon::GetConnectingImageForNetworkType(
  199. NetworkType::kCellular, icon_type);
  200. }
  201. const NetworkStateProperties* active_cellular = model_->active_cellular();
  202. if (!active_cellular) {
  203. if (animating)
  204. *animating = false;
  205. return network_icon::GetDisconnectedImageForNetworkType(
  206. NetworkType::kCellular);
  207. }
  208. return network_icon::GetImageForNonVirtualNetwork(
  209. active_cellular, icon_type, false /* show_vpn_badge */, animating);
  210. }
  211. gfx::ImageSkia ActiveNetworkIcon::GetDefaultImageImpl(
  212. const NetworkStateProperties* network,
  213. network_icon::IconType icon_type,
  214. bool* animating) {
  215. if (!network) {
  216. VLOG(1) << __func__ << ": No network";
  217. return GetDefaultImageForNoNetwork(icon_type, animating);
  218. }
  219. // Don't show connected Ethernet in the tray unless a VPN is present.
  220. const NetworkStateProperties* active_vpn = model_->active_vpn();
  221. if (network->type == NetworkType::kEthernet && IsTrayIcon(icon_type) &&
  222. !active_vpn) {
  223. if (animating)
  224. *animating = false;
  225. VLOG(1) << __func__ << ": Ethernet: No icon";
  226. return gfx::ImageSkia();
  227. }
  228. // Connected network with a connecting VPN.
  229. if (chromeos::network_config::StateIsConnected(network->connection_state) &&
  230. active_vpn &&
  231. active_vpn->connection_state == ConnectionStateType::kConnecting) {
  232. if (animating)
  233. *animating = true;
  234. VLOG(1) << __func__ << ": Connected with connecting VPN";
  235. return network_icon::GetConnectedNetworkWithConnectingVpnImage(network,
  236. icon_type);
  237. }
  238. // Default behavior: connected or connecting network, possibly with VPN badge.
  239. bool show_vpn_badge = !!active_vpn;
  240. VLOG(1) << __func__ << ": Network: " << network->name;
  241. return network_icon::GetImageForNonVirtualNetwork(network, icon_type,
  242. show_vpn_badge, animating);
  243. }
  244. gfx::ImageSkia ActiveNetworkIcon::GetDefaultImageForNoNetwork(
  245. network_icon::IconType icon_type,
  246. bool* animating) {
  247. if (animating)
  248. *animating = false;
  249. if (model_->GetDeviceState(NetworkType::kWiFi) == DeviceStateType::kEnabled) {
  250. // WiFi is enabled but no connections available.
  251. return network_icon::GetImageForWiFiNoConnections(icon_type);
  252. }
  253. // WiFi is disabled, show a full icon with a strikethrough.
  254. return network_icon::GetImageForWiFiEnabledState(false /* not enabled*/,
  255. icon_type);
  256. }
  257. void ActiveNetworkIcon::SetCellularUninitializedMsg() {
  258. const DeviceStateProperties* cellular =
  259. model_->GetDevice(NetworkType::kCellular);
  260. if (cellular && cellular->device_state == DeviceStateType::kUninitialized) {
  261. cellular_uninitialized_msg_ = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR;
  262. uninitialized_state_time_ = base::Time::Now();
  263. return;
  264. }
  265. // If cellular is scanning, we want to show a 'connecting' image. However,
  266. // there may be some cases where cellular's scanning property is true while
  267. // the device is disabling. In this instance, we don't want to show
  268. // 'connecting'. Only set cellular_uninitialized_msg_ to scanning if the
  269. // device is scanning and enabled or enabling.
  270. if (cellular &&
  271. (cellular->device_state == DeviceStateType::kEnabled ||
  272. cellular->device_state == DeviceStateType::kEnabling) &&
  273. cellular->scanning) {
  274. cellular_uninitialized_msg_ = IDS_ASH_STATUS_TRAY_MOBILE_SCANNING;
  275. uninitialized_state_time_ = base::Time::Now();
  276. return;
  277. }
  278. // If cellular is not scanning and cellular device is enabled reset cellular
  279. // initializing state.
  280. if (cellular && !cellular->scanning &&
  281. (cellular->device_state == DeviceStateType::kEnabled ||
  282. cellular->device_state == DeviceStateType::kEnabling)) {
  283. cellular_uninitialized_msg_ = 0;
  284. }
  285. // There can be a delay between leaving the Initializing state and when
  286. // a Cellular device shows up, so keep showing the initializing
  287. // animation for a bit to avoid flashing the disconnect icon.
  288. const int kInitializingDelaySeconds = 1;
  289. base::TimeDelta dtime = base::Time::Now() - uninitialized_state_time_;
  290. if (dtime.InSeconds() >= kInitializingDelaySeconds)
  291. cellular_uninitialized_msg_ = 0;
  292. }
  293. // TrayNetworkStateObserver
  294. void ActiveNetworkIcon::ActiveNetworkStateChanged() {
  295. SetCellularUninitializedMsg();
  296. }
  297. void ActiveNetworkIcon::DeviceStateListChanged() {
  298. SetCellularUninitializedMsg();
  299. }
  300. void ActiveNetworkIcon::NetworkListChanged() {
  301. if (purge_timer_.IsRunning())
  302. return;
  303. purge_timer_.Start(FROM_HERE, base::Milliseconds(kPurgeDelayMs),
  304. base::BindOnce(&ActiveNetworkIcon::PurgeNetworkIconCache,
  305. weak_ptr_factory_.GetWeakPtr()));
  306. }
  307. void ActiveNetworkIcon::PurgeNetworkIconCache() {
  308. model_->cros_network_config()->GetNetworkStateList(
  309. NetworkFilter::New(FilterType::kVisible, NetworkType::kAll,
  310. /*limit=*/0),
  311. base::BindOnce(
  312. [](std::vector<
  313. chromeos::network_config::mojom::NetworkStatePropertiesPtr>
  314. networks) {
  315. std::set<std::string> network_guids;
  316. for (const auto& iter : networks) {
  317. network_guids.insert(iter->guid);
  318. }
  319. network_icon::PurgeNetworkIconCache(network_guids);
  320. }));
  321. }
  322. } // namespace ash