1 // Copyright 2014 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
5 #include "apps/shell/browser/shell_network_controller_chromeos.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/time/time.h"
12 #include "chromeos/network/network_connection_handler.h"
13 #include "chromeos/network/network_handler.h"
14 #include "chromeos/network/network_handler_callbacks.h"
15 #include "chromeos/network/network_state.h"
16 #include "chromeos/network/network_state_handler.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
18
19 namespace apps {
20
21 namespace {
22
23 // Frequency at which networks should be scanned when not connected.
24 const int kScanIntervalSec = 10;
25
HandleEnableWifiError(const std::string & error_name,scoped_ptr<base::DictionaryValue> error_data)26 void HandleEnableWifiError(
27 const std::string& error_name,
28 scoped_ptr<base::DictionaryValue> error_data) {
29 LOG(WARNING) << "Unable to enable wifi: " << error_name;
30 }
31
32 // Returns a human-readable name for the network described by |state|.
GetNetworkName(const chromeos::NetworkState & state)33 std::string GetNetworkName(const chromeos::NetworkState& state) {
34 return !state.name().empty() ? state.name() :
35 base::StringPrintf("[%s]", state.type().c_str());
36 }
37
38 // Returns true if shill is either connected or connecting to a network.
IsConnectedOrConnecting()39 bool IsConnectedOrConnecting() {
40 chromeos::NetworkStateHandler* state_handler =
41 chromeos::NetworkHandler::Get()->network_state_handler();
42 return state_handler->ConnectedNetworkByType(
43 chromeos::NetworkTypePattern::Default()) ||
44 state_handler->ConnectingNetworkByType(
45 chromeos::NetworkTypePattern::Default());
46 }
47
48 } // namespace
49
ShellNetworkController()50 ShellNetworkController::ShellNetworkController()
51 : waiting_for_connection_result_(false),
52 weak_ptr_factory_(this) {
53 chromeos::NetworkHandler::Initialize();
54 chromeos::NetworkStateHandler* state_handler =
55 chromeos::NetworkHandler::Get()->network_state_handler();
56 DCHECK(state_handler);
57 state_handler->AddObserver(this, FROM_HERE);
58 state_handler->SetTechnologyEnabled(
59 chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi),
60 true, base::Bind(&HandleEnableWifiError));
61
62 if (!IsConnectedOrConnecting()) {
63 RequestScan();
64 SetScanningEnabled(true);
65 ConnectIfUnconnected();
66 }
67 }
68
~ShellNetworkController()69 ShellNetworkController::~ShellNetworkController() {
70 chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver(
71 this, FROM_HERE);
72 chromeos::NetworkHandler::Shutdown();
73 }
74
NetworkListChanged()75 void ShellNetworkController::NetworkListChanged() {
76 VLOG(1) << "Network list changed";
77 ConnectIfUnconnected();
78 }
79
DefaultNetworkChanged(const chromeos::NetworkState * state)80 void ShellNetworkController::DefaultNetworkChanged(
81 const chromeos::NetworkState* state) {
82 if (state) {
83 VLOG(1) << "Default network state changed:"
84 << " name=" << GetNetworkName(*state)
85 << " path=" << state->path()
86 << " state=" << state->connection_state();
87 } else {
88 VLOG(1) << "Default network state changed: [no network]";
89 }
90
91 if (IsConnectedOrConnecting()) {
92 SetScanningEnabled(false);
93 } else {
94 SetScanningEnabled(true);
95 ConnectIfUnconnected();
96 }
97 }
98
SetScanningEnabled(bool enabled)99 void ShellNetworkController::SetScanningEnabled(bool enabled) {
100 const bool currently_enabled = scan_timer_.IsRunning();
101 if (enabled == currently_enabled)
102 return;
103
104 VLOG(1) << (enabled ? "Starting" : "Stopping") << " scanning";
105 if (enabled) {
106 scan_timer_.Start(FROM_HERE,
107 base::TimeDelta::FromSeconds(kScanIntervalSec),
108 this, &ShellNetworkController::RequestScan);
109 } else {
110 scan_timer_.Stop();
111 }
112 }
113
RequestScan()114 void ShellNetworkController::RequestScan() {
115 VLOG(1) << "Requesting scan";
116 chromeos::NetworkHandler::Get()->network_state_handler()->RequestScan();
117 }
118
119 // Attempts to connect to an available network if not already connecting or
120 // connected.
ConnectIfUnconnected()121 void ShellNetworkController::ConnectIfUnconnected() {
122 chromeos::NetworkHandler* handler = chromeos::NetworkHandler::Get();
123 DCHECK(handler);
124 if (waiting_for_connection_result_ || IsConnectedOrConnecting())
125 return;
126
127 chromeos::NetworkStateHandler::NetworkStateList state_list;
128 handler->network_state_handler()->GetVisibleNetworkListByType(
129 chromeos::NetworkTypePattern::WiFi(), &state_list);
130 for (chromeos::NetworkStateHandler::NetworkStateList::const_iterator it =
131 state_list.begin(); it != state_list.end(); ++it) {
132 const chromeos::NetworkState* state = *it;
133 DCHECK(state);
134 if (!state->connectable())
135 continue;
136
137 VLOG(1) << "Connecting to network " << GetNetworkName(*state)
138 << " with path " << state->path() << " and strength "
139 << state->signal_strength();
140 waiting_for_connection_result_ = true;
141 handler->network_connection_handler()->ConnectToNetwork(
142 state->path(),
143 base::Bind(&ShellNetworkController::HandleConnectionSuccess,
144 weak_ptr_factory_.GetWeakPtr()),
145 base::Bind(&ShellNetworkController::HandleConnectionError,
146 weak_ptr_factory_.GetWeakPtr()),
147 false /* check_error_state */);
148
149 return;
150 }
151
152 VLOG(1) << "Didn't find any connectable networks";
153 }
154
HandleConnectionSuccess()155 void ShellNetworkController::HandleConnectionSuccess() {
156 VLOG(1) << "Successfully connected to network";
157 waiting_for_connection_result_ = false;
158 }
159
HandleConnectionError(const std::string & error_name,scoped_ptr<base::DictionaryValue> error_data)160 void ShellNetworkController::HandleConnectionError(
161 const std::string& error_name,
162 scoped_ptr<base::DictionaryValue> error_data) {
163 LOG(WARNING) << "Unable to connect to network: " << error_name;
164 waiting_for_connection_result_ = false;
165 }
166
167 } // namespace apps
168