1010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// found in the LICENSE file.
4010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
5010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "apps/shell/browser/shell_network_controller_chromeos.h"
6010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
7010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/bind.h"
8010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/location.h"
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/logging.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/strings/stringprintf.h"
11010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/time/time.h"
12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_connection_handler.h"
13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_handler.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_handler_callbacks.h"
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_state.h"
16010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_state_handler.h"
17010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
18010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
19010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace apps {
20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace {
22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Frequency at which networks should be scanned when not connected.
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const int kScanIntervalSec = 10;
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void HandleEnableWifiError(
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::string& error_name,
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scoped_ptr<base::DictionaryValue> error_data) {
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  LOG(WARNING) << "Unable to enable wifi: " << error_name;
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Returns a human-readable name for the network described by |state|.
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)std::string GetNetworkName(const chromeos::NetworkState& state) {
34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return !state.name().empty() ? state.name() :
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      base::StringPrintf("[%s]", state.type().c_str());
36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Returns true if shill is either connected or connecting to a network.
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool IsConnectedOrConnecting() {
40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  chromeos::NetworkStateHandler* state_handler =
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      chromeos::NetworkHandler::Get()->network_state_handler();
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return state_handler->ConnectedNetworkByType(
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)             chromeos::NetworkTypePattern::Default()) ||
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)         state_handler->ConnectingNetworkByType(
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)             chromeos::NetworkTypePattern::Default());
46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)ShellNetworkController::ShellNetworkController()
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : waiting_for_connection_result_(false),
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      weak_ptr_factory_(this) {
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  chromeos::NetworkHandler::Initialize();
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  chromeos::NetworkStateHandler* state_handler =
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      chromeos::NetworkHandler::Get()->network_state_handler();
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(state_handler);
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  state_handler->AddObserver(this, FROM_HERE);
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  state_handler->SetTechnologyEnabled(
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi),
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      true, base::Bind(&HandleEnableWifiError));
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!IsConnectedOrConnecting()) {
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RequestScan();
64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    SetScanningEnabled(true);
65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ConnectIfUnconnected();
66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)ShellNetworkController::~ShellNetworkController() {
70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver(
71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      this, FROM_HERE);
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  chromeos::NetworkHandler::Shutdown();
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::NetworkListChanged() {
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  VLOG(1) << "Network list changed";
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ConnectIfUnconnected();
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::DefaultNetworkChanged(
81010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const chromeos::NetworkState* state) {
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (state) {
83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    VLOG(1) << "Default network state changed:"
84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            << " name=" << GetNetworkName(*state)
85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            << " path=" << state->path()
86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            << " state=" << state->connection_state();
87010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  } else {
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    VLOG(1) << "Default network state changed: [no network]";
89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (IsConnectedOrConnecting()) {
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    SetScanningEnabled(false);
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  } else {
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    SetScanningEnabled(true);
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ConnectIfUnconnected();
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::SetScanningEnabled(bool enabled) {
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const bool currently_enabled = scan_timer_.IsRunning();
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (enabled == currently_enabled)
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  VLOG(1) << (enabled ? "Starting" : "Stopping") << " scanning";
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (enabled) {
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scan_timer_.Start(FROM_HERE,
107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                      base::TimeDelta::FromSeconds(kScanIntervalSec),
108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                      this, &ShellNetworkController::RequestScan);
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  } else {
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scan_timer_.Stop();
111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
112010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::RequestScan() {
115010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  VLOG(1) << "Requesting scan";
116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  chromeos::NetworkHandler::Get()->network_state_handler()->RequestScan();
117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
118010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
119010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Attempts to connect to an available network if not already connecting or
120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// connected.
121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::ConnectIfUnconnected() {
122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  chromeos::NetworkHandler* handler = chromeos::NetworkHandler::Get();
123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(handler);
124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (waiting_for_connection_result_ || IsConnectedOrConnecting())
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  chromeos::NetworkStateHandler::NetworkStateList state_list;
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  handler->network_state_handler()->GetVisibleNetworkListByType(
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      chromeos::NetworkTypePattern::WiFi(), &state_list);
130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (chromeos::NetworkStateHandler::NetworkStateList::const_iterator it =
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       state_list.begin(); it != state_list.end(); ++it) {
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const chromeos::NetworkState* state = *it;
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK(state);
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (!state->connectable())
135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      continue;
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    VLOG(1) << "Connecting to network " << GetNetworkName(*state)
138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            << " with path " << state->path() << " and strength "
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            << state->signal_strength();
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    waiting_for_connection_result_ = true;
141010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    handler->network_connection_handler()->ConnectToNetwork(
142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        state->path(),
143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        base::Bind(&ShellNetworkController::HandleConnectionSuccess,
144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr()),
145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        base::Bind(&ShellNetworkController::HandleConnectionError,
146010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr()),
147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        false /* check_error_state */);
148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
151010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  VLOG(1) << "Didn't find any connectable networks";
153010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
154010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::HandleConnectionSuccess() {
156010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  VLOG(1) << "Successfully connected to network";
157010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  waiting_for_connection_result_ = false;
158010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
159010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
160010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::HandleConnectionError(
161010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::string& error_name,
162010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scoped_ptr<base::DictionaryValue> error_data) {
163010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  LOG(WARNING) << "Unable to connect to network: " << error_name;
164010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  waiting_for_connection_result_ = false;
165010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
166010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
167010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace apps
168