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