diff options
author | stevenjb@google.com <stevenjb@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 06:40:33 +0000 |
---|---|---|
committer | stevenjb@google.com <stevenjb@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 06:40:33 +0000 |
commit | c364790639ff2ac3ea6ec187cd71ce2908b76548 (patch) | |
tree | 0ea4f83a66bb3526da0b849a3e7cdd2c0257568b | |
parent | 0c6f3b0c5f6409496fcecab0819b062f36d9b113 (diff) | |
download | chromium_src-c364790639ff2ac3ea6ec187cd71ce2908b76548.zip chromium_src-c364790639ff2ac3ea6ec187cd71ce2908b76548.tar.gz chromium_src-c364790639ff2ac3ea6ec187cd71ce2908b76548.tar.bz2 |
Add VPN UI
* Add 'Private networks' submenu to the network menu, which lists active virtual networks and has 'Add private network...' item
* Settings UI is incomplete and currently consists only of an overlay badge on the active wireless network when there is an active VPN.
Note: Code is ready for review, but requires changes to flimflam to be testable.
BUG=chromium-os:11815
TEST=Test conencting to PSK and OpenVPN networks
Review URL: http://codereview.chromium.org/6733013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81710 0039d316-1c4b-4281-b951-d872f2087c98
27 files changed, 2516 insertions, 902 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 6bd79c4..2ff3b9c 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4213,6 +4213,12 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_FLAGS_ENABLE_EXPERIMENTAL_EAP_DESCRIPTION" desc="Description of the 'Experimental Wi-Fi EAP methods' lab."> Experimental support for additional Wi-Fi Extensible Authentication Protocol methods, such as EAP-TLS and LEAP. </message> + <message name="IDS_FLAGS_ENABLE_VPN_NAME" desc="Title for the flag to enable VPN support"> + VPN support + </message> + <message name="IDS_FLAGS_ENABLE_VPN_DESCRIPTION" desc="Description for the flag to enable VPN support"> + Show Private networks in the Network menu to enable conencting to a VPN. + </message> <!-- Crashes --> <message name="IDS_CRASHES_TITLE" desc="Title for the chrome://crashes page."> @@ -9848,6 +9854,9 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_OPTIONS_SETTINGS_JOIN_WIFI_NETWORKS" desc="The title for the dialog to join a wifi network."> Join Wi-Fi network </message> + <message name="IDS_OPTIONS_SETTINGS_ADD_VPN" desc="In the settings tab, the text on the button to add a private network."> + Add private network + </message> <message name="IDS_OPTIONS_SETTINGS_ENABLE_DATA_ROAMING" desc="In the settings tab, the text next to the checkbox for data roaming."> Allow mobile data roaming </message> @@ -10007,8 +10016,8 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PURCHASE_MORE" desc="In settings Internet options, the title for buy cellular data plan button."> Buy data plan... </message> - <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_CREDENTIALS" desc="In settings Internet options, the label for invalid passphrase or identity input."> - Password is too short or invalid. + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_UNKNOWN_ERROR" desc="In settings Internet options, the label for an unknown connection error."> + Failed to connect to network. </message> <message name="IDS_OPTIONS_SETTINGS_INTERNET_CELL_PLAN_NAME" desc="In settings Internet options, the label displayed next to cellular plan name."> Plan name: @@ -10094,6 +10103,36 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CONNECT_TITLE" desc="In settings Internet options, Title of the overlay when the user is not connected and can."> Connect to network </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_PSK" desc="In settings Internet options, a string specifying L2TP/IPSec + PSK."> + L2TP/IPSec + Pre-shared key + </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_USER_CERT" desc="In settings Internet options, a string specifying L2TP/IPSec + User Certificate."> + L2TP/IPSec + User certificate + </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_OPEN_VPN" desc="In settings Internet options, a string specifying OpenVPN."> + OpenVPN + </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME" desc="In settings Internet options, a string specifying VPN service name."> + Service name: + </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME" desc="In settings Internet options, a string specifying VPN server hostname."> + Server hostname: + </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE" desc="In settings Internet options, a string specifying VPN provider type."> + Provider type: + </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PSK_PASSPHRASE" desc="In settings Internet options, a string specifying VPN PSK passphrase."> + Pre-shared key: + </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_CERT" desc="In settings Internet options, a string specifying VPN user certificate."> + User certificate: + </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME" desc="In settings Internet options, a string specifying VPN username."> + Username: + </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_PASSPHRASE" desc="In settings Internet options, a string specifying VPN user passphrase."> + Password: + </message> <message name="IDS_NETWORK_RECONNECT_TITLE" desc="In network menu, title of the reconnect button that allows user to retry connection on error."> Reconnect </message> @@ -10980,6 +11019,15 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_STATUSBAR_NETWORK_OPEN_PROXY_SETTINGS_DIALOG" desc="The menu item in the network menu button at login screen for opening the options dialog"> Proxy settings... </message> + <message name="IDS_STATUSBAR_NETWORK_PRIVATE_NETWORKS" desc="In the network status menu, the text for submenu of private networks."> + Private networks + </message> + <message name="IDS_STATUSBAR_NETWORK_ADD_VPN" desc="In the network status menu, the text in Private networks submenu to add a private network."> + Add private network... + </message> + <message name="IDS_STATUSBAR_NETWORK_DISCONNECT_VPN" desc="In the network status menu, the text in Private networks submenu to disconnect from a private network."> + Disconnect private network + </message> <message name="IDS_STATUSBAR_NO_NETWORKS_MESSAGE" desc="No networks are available"> No networks are available </message> @@ -11218,7 +11266,7 @@ Keep your key file in a safe place. You will need it to create new versions of y <!-- Network error strings for ChromeOS --> <message name="IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN" desc="Network error in about:network: UNKNOWN"> - Unknown + Unknown network error </message> <message name="IDS_CHROMEOS_NETWORK_ERROR_OUT_OF_RANGE" desc="Network error in about:network: OUT_OF_RANGE"> Out of range diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 924b486..d5bb64e 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -309,6 +309,18 @@ const Experiment kExperiments[] = { SINGLE_VALUE_TYPE("") #endif }, + { + "enable-vpn", + IDS_FLAGS_ENABLE_VPN_NAME, + IDS_FLAGS_ENABLE_VPN_DESCRIPTION, + kOsCrOS, +#if defined(OS_CHROMEOS) + // The switch exists only on Chrome OS. + SINGLE_VALUE_TYPE(switches::kEnableVPN) +#else + SINGLE_VALUE_TYPE("") +#endif + }, }; const Experiment* experiments = kExperiments; diff --git a/chrome/browser/automation/testing_automation_provider_chromeos.cc b/chrome/browser/automation/testing_automation_provider_chromeos.cc index 24faad4..875066a 100644 --- a/chrome/browser/automation/testing_automation_provider_chromeos.cc +++ b/chrome/browser/automation/testing_automation_provider_chromeos.cc @@ -459,7 +459,7 @@ void TestingAutomationProvider::ConnectToHiddenWifiNetwork( new SSIDConnectObserver(this, reply_message, ssid); network_library->ConnectToWifiNetwork(connection_security, ssid, password, - identity, certpath, false); + identity, certpath); } void TestingAutomationProvider::DisconnectFromWifiNetwork( @@ -475,7 +475,7 @@ void TestingAutomationProvider::DisconnectFromWifiNetwork( return; } - network_library->DisconnectFromWirelessNetwork(wifi); + network_library->DisconnectFromNetwork(wifi); reply.SendSuccess(NULL); } diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc index 958fe56..d03c149 100644 --- a/chrome/browser/browser_about_handler.cc +++ b/chrome/browser/browser_about_handler.cc @@ -363,11 +363,180 @@ std::string AboutAbout() { } #if defined(OS_CHROMEOS) + +// Html output helper functions +// TODO(stevenjb): L10N this. + +// Helper function to wrap Html with <th> tag. +static std::string WrapWithTH(std::string text) { + return "<th>" + text + "</th>"; +} + +// Helper function to wrap Html with <td> tag. +static std::string WrapWithTD(std::string text) { + return "<td>" + text + "</td>"; +} + +// Helper function to create an Html table header for a Network. +static std::string ToHtmlTableHeader(const chromeos::Network* network) { + std::string str = + WrapWithTH("Name") + + WrapWithTH("Active") + + WrapWithTH("State"); + if (network->type() == chromeos::TYPE_WIFI || + network->type() == chromeos::TYPE_CELLULAR) { + str += WrapWithTH("Auto-Connect"); + str += WrapWithTH("Strength"); + } + if (network->type() == chromeos::TYPE_WIFI) { + str += WrapWithTH("Encryption"); + str += WrapWithTH("Passphrase"); + str += WrapWithTH("Identity"); + str += WrapWithTH("Certificate"); + } + if (network->type() == chromeos::TYPE_CELLULAR) { + str += WrapWithTH("Technology"); + str += WrapWithTH("Connectivity"); + str += WrapWithTH("Activation"); + str += WrapWithTH("Roaming"); + } + if (network->type() == chromeos::TYPE_VPN) { + str += WrapWithTH("Host"); + str += WrapWithTH("Provider Type"); + str += WrapWithTH("PSK Passphrase"); + str += WrapWithTH("Username"); + str += WrapWithTH("User Passphrase"); + } + str += WrapWithTH("Error"); + str += WrapWithTH("IP Address"); + return str; +} + +// Helper function to create an Html table row for a Network. +static std::string ToHtmlTableRow(const chromeos::Network* network) { + std::string str = + WrapWithTD(network->name()) + + WrapWithTD(base::IntToString(network->is_active())) + + WrapWithTD(network->GetStateString()); + if (network->type() == chromeos::TYPE_WIFI || + network->type() == chromeos::TYPE_CELLULAR) { + const chromeos::WirelessNetwork* wireless = + static_cast<const chromeos::WirelessNetwork*>(network); + str += WrapWithTD(base::IntToString(wireless->auto_connect())); + str += WrapWithTD(base::IntToString(wireless->strength())); + } + if (network->type() == chromeos::TYPE_WIFI) { + const chromeos::WifiNetwork* wifi = + static_cast<const chromeos::WifiNetwork*>(network); + str += WrapWithTD(wifi->GetEncryptionString()); + str += WrapWithTD(std::string(wifi->passphrase().length(), '*')); + str += WrapWithTD(wifi->identity()); + str += WrapWithTD(wifi->cert_path()); + } + if (network->type() == chromeos::TYPE_CELLULAR) { + const chromeos::CellularNetwork* cell = + static_cast<const chromeos::CellularNetwork*>(network); + str += WrapWithTH(cell->GetNetworkTechnologyString()); + str += WrapWithTH(cell->GetConnectivityStateString()); + str += WrapWithTH(cell->GetActivationStateString()); + str += WrapWithTH(cell->GetRoamingStateString()); + } + if (network->type() == chromeos::TYPE_VPN) { + const chromeos::VirtualNetwork* vpn = + static_cast<const chromeos::VirtualNetwork*>(network); + str += WrapWithTH(vpn->server_hostname()); + str += WrapWithTH(vpn->GetProviderTypeString()); + str += WrapWithTD(std::string(vpn->psk_passphrase().length(), '*')); + str += WrapWithTH(vpn->username()); + str += WrapWithTD(std::string(vpn->user_passphrase().length(), '*')); + } + str += WrapWithTD(network->failed() ? network->GetErrorString() : ""); + str += WrapWithTD(network->ip_address()); + return str; +} + +std::string GetNetworkHtmlInfo(int refresh) { + chromeos::NetworkLibrary* cros = + chromeos::CrosLibrary::Get()->GetNetworkLibrary(); + std::string output; + output.append("<html><head><title>About Network</title>"); + if (refresh > 0) + output.append("<meta http-equiv=\"refresh\" content=\"" + + base::IntToString(refresh) + "\"/>"); + output.append("</head><body>"); + if (refresh > 0) { + output.append("(Auto-refreshing page every " + + base::IntToString(refresh) + "s)"); + } else { + output.append("(To auto-refresh this page: about:network/<secs>)"); + } + + if (cros->ethernet_enabled()) { + output.append("<h3>Ethernet:</h3><table border=1>"); + const chromeos::EthernetNetwork* ethernet = cros->ethernet_network(); + if (ethernet) { + output.append("<tr>" + ToHtmlTableHeader(ethernet) + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(ethernet) + "</tr>"); + } + } + + if (cros->wifi_enabled()) { + output.append("</table><h3>Wifi Networks:</h3><table border=1>"); + const chromeos::WifiNetworkVector& wifi_networks = cros->wifi_networks(); + for (size_t i = 0; i < wifi_networks.size(); ++i) { + if (i == 0) + output.append("<tr>" + ToHtmlTableHeader(wifi_networks[i]) + + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(wifi_networks[i]) + "</tr>"); + } + } + + if (cros->cellular_enabled()) { + output.append("</table><h3>Cellular Networks:</h3><table border=1>"); + const chromeos::CellularNetworkVector& cellular_networks = + cros->cellular_networks(); + for (size_t i = 0; i < cellular_networks.size(); ++i) { + if (i == 0) + output.append("<tr>" + ToHtmlTableHeader(cellular_networks[i]) + + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(cellular_networks[i]) + "</tr>"); + } + } + + { + output.append("</table><h3>Virtual Networks:</h3><table border=1>"); + const chromeos::VirtualNetworkVector& virtual_networks = + cros->virtual_networks(); + for (size_t i = 0; i < virtual_networks.size(); ++i) { + if (i == 0) + output.append("<tr>" + ToHtmlTableHeader(virtual_networks[i]) + + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(virtual_networks[i]) + "</tr>"); + } + } + + { + output.append( + "</table><h3>Remembered Wi-Fi Networks:</h3><table border=1>"); + const chromeos::WifiNetworkVector& remembered_wifi_networks = + cros->remembered_wifi_networks(); + for (size_t i = 0; i < remembered_wifi_networks.size(); ++i) { + if (i == 0) + output.append("<tr>" + + ToHtmlTableHeader(remembered_wifi_networks[i]) + "</tr>"); + output.append("<tr>" + ToHtmlTableRow(remembered_wifi_networks[i]) + + "</tr>"); + } + } + + output.append("</table></body></html>"); + return output; +} + std::string AboutNetwork(const std::string& query) { int refresh; base::StringToInt(query, &refresh); - return chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> - GetHtmlInfo(refresh); + return GetNetworkHtmlInfo(refresh); } #endif diff --git a/chrome/browser/chromeos/cros/mock_network_library.h b/chrome/browser/chromeos/cros/mock_network_library.h index efc5b17..014ee9a 100644 --- a/chrome/browser/chromeos/cros/mock_network_library.h +++ b/chrome/browser/chromeos/cros/mock_network_library.h @@ -70,6 +70,8 @@ class MockNetworkLibrary : public NetworkLibrary { WifiNetwork*(const std::string&)); MOCK_CONST_METHOD1(FindCellularNetworkByPath, CellularNetwork*(const std::string&)); + MOCK_CONST_METHOD1(FindVirtualNetworkByPath, + VirtualNetwork*(const std::string&)); MOCK_CONST_METHOD1(GetDataPlans, CellularDataPlanVector*(const std::string&)); MOCK_CONST_METHOD1(GetSignificantDataPlan, @@ -84,17 +86,22 @@ class MockNetworkLibrary : public NetworkLibrary { MOCK_METHOD1(GetWifiAccessPoints, bool(WifiAccessPointVector*)); MOCK_METHOD1(ConnectToWifiNetwork, void(WifiNetwork*)); MOCK_METHOD1(ConnectToWifiNetwork, void(const std::string&)); - MOCK_METHOD6(ConnectToWifiNetwork, void(ConnectionSecurity security, + MOCK_METHOD5(ConnectToWifiNetwork, void(ConnectionSecurity security, const std::string&, const std::string&, const std::string&, - const std::string&, - bool)); + const std::string&)); MOCK_METHOD1(ConnectToCellularNetwork, void(CellularNetwork*)); + MOCK_METHOD1(ConnectToVirtualNetwork, void(VirtualNetwork*)); + MOCK_METHOD5(ConnectToVirtualNetworkPSK, void(const std::string&, + const std::string&, + const std::string&, + const std::string&, + const std::string&)); MOCK_METHOD0(SignalCellularPlanPayment, void(void)); MOCK_METHOD0(HasRecentCellularPlanPayment, bool(void)); - MOCK_METHOD1(DisconnectFromWirelessNetwork, void(const WirelessNetwork*)); + MOCK_METHOD1(DisconnectFromNetwork, void(const Network*)); MOCK_METHOD1(ForgetWifiNetwork, void(const std::string&)); MOCK_CONST_METHOD0(ethernet_available, bool(void)); @@ -108,6 +115,8 @@ class MockNetworkLibrary : public NetworkLibrary { MOCK_CONST_METHOD0(wifi_scanning, bool(void)); MOCK_CONST_METHOD0(active_network, const Network*(void)); + MOCK_CONST_METHOD0(connected_network, const Network*(void)); + MOCK_CONST_METHOD0(offline_mode, bool(void)); MOCK_METHOD1(EnableEthernetNetworkDevice, void(bool)); diff --git a/chrome/browser/chromeos/cros/network_library.cc b/chrome/browser/chromeos/cros/network_library.cc index 54dd258..270c177 100644 --- a/chrome/browser/chromeos/cros/network_library.cc +++ b/chrome/browser/chromeos/cros/network_library.cc @@ -133,6 +133,8 @@ const char* kErrorProperty = "Error"; const char* kActiveProfileProperty = "ActiveProfile"; const char* kEntriesProperty = "Entries"; const char* kDevicesProperty = "Devices"; +const char* kProviderProperty = "Provider"; +const char* kHostProperty = "Host"; // Flimflam property names for SIMLock status. const char* kSIMLockStatusProperty = "Cellular.SIMLockStatus"; @@ -185,6 +187,14 @@ const char* kSecurityRsn = "rsn"; const char* kSecurity8021x = "802_1x"; const char* kSecurityNone = "none"; +// Flimflam L2TPIPsec property names. +const char* kL2TPIPSecCACertProperty = "L2TPIPsec.CACert"; +const char* kL2TPIPSecCertProperty = "L2TPIPsec.Cert"; +const char* kL2TPIPSecKeyProperty = "L2TPIPsec.Key"; +const char* kL2TPIPSecPSKProperty = "L2TPIPsec.PSK"; +const char* kL2TPIPSecUserProperty = "L2TPIPsec.User"; +const char* kL2TPIPSecPasswordProperty = "L2TPIPsec.Password"; + // Flimflam EAP property names. // See src/third_party/flimflam/doc/service-api.txt. const char* kEapIdentityProperty = "EAP.Identity"; @@ -220,6 +230,11 @@ const std::string& kEapPhase2AuthTTLSMSCHAP = "autheap=MSCHAP"; const std::string& kEapPhase2AuthTTLSPAP = "autheap=PAP"; const std::string& kEapPhase2AuthTTLSCHAP = "autheap=CHAP"; +// Flimflam VPN provider types. +const char* kProviderL2tpIpsec = "l2tpipsec"; +const char* kProviderOpenVpn = "openvpn"; + + // Flimflam state options. const char* kStateIdle = "idle"; const char* kStateCarrier = "carrier"; @@ -320,6 +335,20 @@ static const char* SecurityToString(ConnectionSecurity security) { return kUnknownString; } +static const char* ProviderTypeToString(VirtualNetwork::ProviderType type) { + switch (type) { + case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: + case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: + return kProviderL2tpIpsec; + case VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: + return kProviderOpenVpn; + case VirtualNetwork::PROVIDER_TYPE_MAX: + break; + } + LOG(ERROR) << "ProviderTypeToString called with unknown type: " << type; + return kUnknownString; +} + //////////////////////////////////////////////////////////////////////////// // Helper class to cache maps of strings to enums. @@ -393,11 +422,18 @@ enum PropertyIndex { PROPERTY_INDEX_FIRMWARE_REVISION, PROPERTY_INDEX_HARDWARE_REVISION, PROPERTY_INDEX_HOME_PROVIDER, + PROPERTY_INDEX_HOST, PROPERTY_INDEX_IDENTITY, PROPERTY_INDEX_IMEI, PROPERTY_INDEX_IMSI, PROPERTY_INDEX_IS_ACTIVE, PROPERTY_INDEX_LAST_DEVICE_UPDATE, + PROPERTY_INDEX_L2TPIPSEC_CA_CERT, + PROPERTY_INDEX_L2TPIPSEC_CERT, + PROPERTY_INDEX_L2TPIPSEC_KEY, + PROPERTY_INDEX_L2TPIPSEC_PASSWORD, + PROPERTY_INDEX_L2TPIPSEC_PSK, + PROPERTY_INDEX_L2TPIPSEC_USER, PROPERTY_INDEX_MANUFACTURER, PROPERTY_INDEX_MDN, PROPERTY_INDEX_MEID, @@ -414,6 +450,7 @@ enum PropertyIndex { PROPERTY_INDEX_PAYMENT_URL, PROPERTY_INDEX_PRL_VERSION, PROPERTY_INDEX_PROFILES, + PROPERTY_INDEX_PROVIDER, PROPERTY_INDEX_ROAMING_STATE, PROPERTY_INDEX_SAVE_CREDENTIALS, PROPERTY_INDEX_SCANNING, @@ -467,10 +504,17 @@ StringToEnum<PropertyIndex>::Pair property_index_table[] = { { kFirmwareRevisionProperty, PROPERTY_INDEX_FIRMWARE_REVISION }, { kHardwareRevisionProperty, PROPERTY_INDEX_HARDWARE_REVISION }, { kHomeProviderProperty, PROPERTY_INDEX_HOME_PROVIDER }, + { kHostProperty, PROPERTY_INDEX_HOST }, { kIdentityProperty, PROPERTY_INDEX_IDENTITY }, { kImeiProperty, PROPERTY_INDEX_IMEI }, { kImsiProperty, PROPERTY_INDEX_IMSI }, { kIsActiveProperty, PROPERTY_INDEX_IS_ACTIVE }, + { kL2TPIPSecCACertProperty, PROPERTY_INDEX_L2TPIPSEC_CA_CERT }, + { kL2TPIPSecCertProperty, PROPERTY_INDEX_L2TPIPSEC_CERT }, + { kL2TPIPSecKeyProperty, PROPERTY_INDEX_L2TPIPSEC_KEY }, + { kL2TPIPSecPasswordProperty, PROPERTY_INDEX_L2TPIPSEC_PASSWORD }, + { kL2TPIPSecPSKProperty, PROPERTY_INDEX_L2TPIPSEC_PSK }, + { kL2TPIPSecUserProperty, PROPERTY_INDEX_L2TPIPSEC_USER }, { kLastDeviceUpdateProperty, PROPERTY_INDEX_LAST_DEVICE_UPDATE }, { kManufacturerProperty, PROPERTY_INDEX_MANUFACTURER }, { kMdnProperty, PROPERTY_INDEX_MDN }, @@ -488,6 +532,7 @@ StringToEnum<PropertyIndex>::Pair property_index_table[] = { { kPassphraseRequiredProperty, PROPERTY_INDEX_PASSPHRASE_REQUIRED }, { kPaymentURLProperty, PROPERTY_INDEX_PAYMENT_URL }, { kProfilesProperty, PROPERTY_INDEX_PROFILES }, + { kProviderProperty, PROPERTY_INDEX_PROVIDER }, { kRoamingStateProperty, PROPERTY_INDEX_ROAMING_STATE }, { kSaveCredentialsProperty, PROPERTY_INDEX_SAVE_CREDENTIALS }, { kScanningProperty, PROPERTY_INDEX_SCANNING }, @@ -577,6 +622,17 @@ static ConnectionError ParseError(const std::string& error) { return parser.Get(error); } +// VirtualNetwork +static VirtualNetwork::ProviderType ParseProviderType(const std::string& mode) { + static StringToEnum<VirtualNetwork::ProviderType>::Pair table[] = { + { kProviderL2tpIpsec, VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK }, + { kProviderOpenVpn, VirtualNetwork::PROVIDER_TYPE_OPEN_VPN }, + }; + static StringToEnum<VirtualNetwork::ProviderType> parser( + table, arraysize(table), VirtualNetwork::PROVIDER_TYPE_MAX); + return parser.Get(mode); +} + // CellularNetwork. static ActivationState ParseActivationState(const std::string& state) { static StringToEnum<ActivationState>::Pair table[] = { @@ -697,59 +753,6 @@ static EAPPhase2Auth ParseEAPPhase2Auth(const std::string& auth) { return parser.Get(auth); } -//////////////////////////////////////////////////////////////////////////// -// Html output helper functions - -// Helper function to wrap Html with <th> tag. -static std::string WrapWithTH(std::string text) { - return "<th>" + text + "</th>"; -} - -// Helper function to wrap Html with <td> tag. -static std::string WrapWithTD(std::string text) { - return "<td>" + text + "</td>"; -} - -// Helper function to create an Html table header for a Network. -static std::string ToHtmlTableHeader(Network* network) { - std::string str; - if (network->type() == TYPE_ETHERNET) { - str += WrapWithTH("Active"); - } else if (network->type() == TYPE_WIFI || network->type() == TYPE_CELLULAR) { - str += WrapWithTH("Name") + WrapWithTH("Active") + - WrapWithTH("Auto-Connect") + WrapWithTH("Strength"); - if (network->type() == TYPE_WIFI) - str += WrapWithTH("Encryption") + WrapWithTH("Passphrase") + - WrapWithTH("Identity") + WrapWithTH("Certificate"); - } - str += WrapWithTH("State") + WrapWithTH("Error") + WrapWithTH("IP Address"); - return str; -} - -// Helper function to create an Html table row for a Network. -static std::string ToHtmlTableRow(Network* network) { - std::string str; - if (network->type() == TYPE_ETHERNET) { - str += WrapWithTD(base::IntToString(network->is_active())); - } else if (network->type() == TYPE_WIFI || network->type() == TYPE_CELLULAR) { - WirelessNetwork* wireless = static_cast<WirelessNetwork*>(network); - str += WrapWithTD(wireless->name()) + - WrapWithTD(base::IntToString(network->is_active())) + - WrapWithTD(base::IntToString(wireless->auto_connect())) + - WrapWithTD(base::IntToString(wireless->strength())); - if (network->type() == TYPE_WIFI) { - WifiNetwork* wifi = static_cast<WifiNetwork*>(network); - str += WrapWithTD(wifi->GetEncryptionString()) + - WrapWithTD(std::string(wifi->passphrase().length(), '*')) + - WrapWithTD(wifi->identity()) + WrapWithTD(wifi->cert_path()); - } - } - str += WrapWithTD(network->GetStateString()) + - WrapWithTD(network->failed() ? network->GetErrorString() : "") + - WrapWithTD(network->ip_address()); - return str; -} - //////////////////////////////////////////////////////////////////////////////// // Misc. @@ -852,10 +855,12 @@ void NetworkDevice::ParseInfo(const DictionaryValue* info) { const std::string& key = *iter; Value* value; bool res = info->GetWithoutPathExpansion(key, &value); - CHECK(res); - int index = property_index_parser().Get(key); - if (!ParseValue(index, value)) - VLOG(1) << "NetworkDevice: Unhandled key: " << key; + DCHECK(res); + if (res) { + int index = property_index_parser().Get(key); + if (!ParseValue(index, value)) + VLOG(1) << "NetworkDevice: Unhandled key: " << key; + } } } @@ -937,57 +942,70 @@ void Network::ParseInfo(const DictionaryValue* info) { const std::string& key = *iter; Value* value; bool res = info->GetWithoutPathExpansion(key, &value); - CHECK(res); - int index = property_index_parser().Get(key); - if (!ParseValue(index, value)) // virtual. - VLOG(1) << "Network: Type: " << type_ << " Unhandled key: " << key; + DCHECK(res); + if (res) { + int index = property_index_parser().Get(key); + if (!ParseValue(index, value)) // virtual. + VLOG(1) << "Network: " << name() + << " Type: " << ConnectionTypeToString(type()) + << " Unhandled key: " << key; + } } } -void Network::SetAutoConnect(bool auto_connect) { - auto_connect_ = auto_connect; - SetBooleanProperty(kAutoConnectProperty, auto_connect); +void Network::SetValueProperty(const char* prop, Value* val) { + DCHECK(prop); + DCHECK(val); + if (!EnsureCrosLoaded()) + return; + SetNetworkServiceProperty(service_path_.c_str(), prop, val); } -void Network::SetStringProperty(const char* prop, const std::string& str) { +void Network::ClearProperty(const char* prop) { + DCHECK(prop); + if (!EnsureCrosLoaded()) + return; + ClearNetworkServiceProperty(service_path_.c_str(), prop); +} + +void Network::SetStringProperty( + const char* prop, const std::string& str, std::string* dest) { + if (dest) + *dest = str; scoped_ptr<Value> value(Value::CreateStringValue(str)); SetValueProperty(prop, value.get()); } -void Network::SetBooleanProperty(const char* prop, bool b) { +void Network::SetOrClearStringProperty(const char* prop, + const std::string& str, + std::string* dest) { + if (str.empty()) { + ClearProperty(prop); + if (dest) + dest->clear(); + } else { + SetStringProperty(prop, str, dest); + } +} + +void Network::SetBooleanProperty(const char* prop, bool b, bool* dest) { + if (dest) + *dest = b; scoped_ptr<Value> value(Value::CreateBooleanValue(b)); SetValueProperty(prop, value.get()); } -void Network::SetIntegerProperty(const char* prop, int i) { +void Network::SetIntegerProperty(const char* prop, int i, int* dest) { + if (dest) + *dest = i; scoped_ptr<Value> value(Value::CreateIntegerValue(i)); SetValueProperty(prop, value.get()); } -void Network::ClearProperty(const char* prop) { - DCHECK(prop); - if (!EnsureCrosLoaded()) - return; - ClearNetworkServiceProperty(service_path_.c_str(), prop); -} - -void Network::SetOrClearStringProperty(const char* prop, - const std::string& str) { - if (str.empty()) - ClearProperty(prop); - else - SetStringProperty(prop, str); -} - -void Network::SetValueProperty(const char* prop, Value* val) { - DCHECK(prop); - DCHECK(val); - if (!EnsureCrosLoaded()) - return; - SetNetworkServiceProperty(service_path_.c_str(), prop, val); +void Network::SetAutoConnect(bool auto_connect) { + SetBooleanProperty(kAutoConnectProperty, auto_connect, &auto_connect_); } -// Used by GetHtmlInfo() which is called from the about:network handler. std::string Network::GetStateString() const { switch (state_) { case STATE_UNKNOWN: @@ -1009,9 +1027,6 @@ std::string Network::GetStateString() const { case STATE_ACTIVATION_FAILURE: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_STATE_ACTIVATION_FAILURE); - default: - // Usually no default, but changes to libcros may add states. - break; } return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_UNRECOGNIZED); } @@ -1046,9 +1061,6 @@ std::string Network::GetErrorString() const { return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_OTASP_FAILED); case ERROR_AAA_FAILED: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_AAA_FAILED); - default: - // Usually no default, but changes to libcros may add errors. - break; } return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_UNRECOGNIZED); } @@ -1072,6 +1084,145 @@ void Network::InitIPAddress() { } //////////////////////////////////////////////////////////////////////////////// +// VirtualNetwork + +bool VirtualNetwork::ParseProviderValue(int index, const Value* value) { + switch (index) { + case PROPERTY_INDEX_HOST: + return value->GetAsString(&server_hostname_); + case PROPERTY_INDEX_NAME: + // Note: shadows Network::name_ property. + return value->GetAsString(&name_); + case PROPERTY_INDEX_TYPE: { + std::string provider_type_string; + if (value->GetAsString(&provider_type_string)) { + provider_type_ = ParseProviderType(provider_type_string); + return true; + } + break; + } + default: + break; + } + return false; +} + +bool VirtualNetwork::ParseValue(int index, const Value* value) { + switch (index) { + case PROPERTY_INDEX_PROVIDER: { + DCHECK_EQ(value->GetType(), Value::TYPE_DICTIONARY); + const DictionaryValue* dict = static_cast<const DictionaryValue*>(value); + for (DictionaryValue::key_iterator iter = dict->begin_keys(); + iter != dict->end_keys(); ++iter) { + const std::string& key = *iter; + Value* v; + bool res = dict->GetWithoutPathExpansion(key, &v); + DCHECK(res); + if (res) { + int index = property_index_parser().Get(key); + if (!ParseProviderValue(index, v)) + VLOG(1) << name() << ": Provider unhandled key: " << key + << " Type: " << v->GetType(); + } + } + return true; + } + case PROPERTY_INDEX_L2TPIPSEC_CA_CERT: + return value->GetAsString(&ca_cert_); + case PROPERTY_INDEX_L2TPIPSEC_PSK: + return value->GetAsString(&psk_passphrase_); + case PROPERTY_INDEX_L2TPIPSEC_CERT: + return value->GetAsString(&user_cert_); + case PROPERTY_INDEX_L2TPIPSEC_KEY: + return value->GetAsString(&user_cert_key_); + case PROPERTY_INDEX_L2TPIPSEC_USER: + return value->GetAsString(&username_); + case PROPERTY_INDEX_L2TPIPSEC_PASSWORD: + return value->GetAsString(&user_passphrase_); + default: + return Network::ParseValue(index, value); + break; + } + return false; +} + +void VirtualNetwork::ParseInfo(const DictionaryValue* info) { + Network::ParseInfo(info); + VLOG(1) << "VPN: " << name() + << " Type: " << ProviderTypeToString(provider_type()); + if (provider_type_ == PROVIDER_TYPE_L2TP_IPSEC_PSK) { + if (!user_cert_.empty()) + provider_type_ = PROVIDER_TYPE_L2TP_IPSEC_USER_CERT; + } +} + +bool VirtualNetwork::NeedMoreInfoToConnect() const { + if (server_hostname_.empty() || username_.empty() || user_passphrase_.empty()) + return true; + switch (provider_type_) { + case PROVIDER_TYPE_L2TP_IPSEC_PSK: + if (psk_passphrase_.empty()) + return true; + break; + case PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: + case PROVIDER_TYPE_OPEN_VPN: + if (user_cert_.empty()) + return true; + break; + case PROVIDER_TYPE_MAX: + break; + } + return false; +} + +void VirtualNetwork::SetCACert(const std::string& ca_cert) { + SetStringProperty(kL2TPIPSecCACertProperty, ca_cert, &ca_cert_); +} + +void VirtualNetwork::SetPSKPassphrase(const std::string& psk_passphrase) { + SetStringProperty(kL2TPIPSecPSKProperty, psk_passphrase, + &psk_passphrase_); +} + +void VirtualNetwork::SetUserCert(const std::string& user_cert) { + SetStringProperty(kL2TPIPSecCertProperty, user_cert, &user_cert_); +} + +void VirtualNetwork::SetUserCertKey(const std::string& key) { + SetStringProperty(kL2TPIPSecKeyProperty, key, &user_cert_key_); +} + +void VirtualNetwork::SetUsername(const std::string& username) { + SetStringProperty(kL2TPIPSecUserProperty, username, &username_); +} + +void VirtualNetwork::SetUserPassphrase(const std::string& user_passphrase) { + SetStringProperty(kL2TPIPSecPasswordProperty, user_passphrase, + &user_passphrase_); +} + +std::string VirtualNetwork::GetProviderTypeString() const { + switch (this->provider_type_) { + case PROVIDER_TYPE_L2TP_IPSEC_PSK: + return l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_PSK); + break; + case PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: + return l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_USER_CERT); + break; + case PROVIDER_TYPE_OPEN_VPN: + return l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_OPEN_VPN); + break; + default: + return l10n_util::GetStringUTF8( + IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN); + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// // WirelessNetwork bool WirelessNetwork::ParseValue(int index, const Value* value) { @@ -1534,12 +1685,12 @@ void WifiNetwork::SetPassphrase(const std::string& passphrase) { user_passphrase_ = passphrase_; // Send the change to flimflam. If the format is valid, it will propagate to // passphrase_ with a service update. - SetStringProperty(kPassphraseProperty, passphrase); + SetStringProperty(kPassphraseProperty, passphrase, NULL); } void WifiNetwork::SetSaveCredentials(bool save_credentials) { - save_credentials_ = save_credentials; - SetBooleanProperty(kSaveCredentialsProperty, save_credentials); + SetBooleanProperty(kSaveCredentialsProperty, save_credentials, + &save_credentials_); } // See src/third_party/flimflam/doc/service-api.txt for properties that @@ -1554,29 +1705,27 @@ void WifiNetwork::EraseCredentials() { } void WifiNetwork::SetIdentity(const std::string& identity) { - identity_ = identity; - SetStringProperty(kIdentityProperty, identity); + SetStringProperty(kIdentityProperty, identity, &identity_); } void WifiNetwork::SetCertPath(const std::string& cert_path) { - cert_path_ = cert_path; - SetStringProperty(kCertPathProperty, cert_path); + SetStringProperty(kCertPathProperty, cert_path, &cert_path_); } void WifiNetwork::SetEAPMethod(EAPMethod method) { eap_method_ = method; switch (method) { case EAP_METHOD_PEAP: - SetStringProperty(kEapMethodProperty, kEapMethodPEAP); + SetStringProperty(kEapMethodProperty, kEapMethodPEAP, NULL); break; case EAP_METHOD_TLS: - SetStringProperty(kEapMethodProperty, kEapMethodTLS); + SetStringProperty(kEapMethodProperty, kEapMethodTLS, NULL); break; case EAP_METHOD_TTLS: - SetStringProperty(kEapMethodProperty, kEapMethodTTLS); + SetStringProperty(kEapMethodProperty, kEapMethodTTLS, NULL); break; case EAP_METHOD_LEAP: - SetStringProperty(kEapMethodProperty, kEapMethodLEAP); + SetStringProperty(kEapMethodProperty, kEapMethodLEAP, NULL); break; default: ClearProperty(kEapMethodProperty); @@ -1594,21 +1743,23 @@ void WifiNetwork::SetEAPPhase2Auth(EAPPhase2Auth auth) { case EAP_PHASE_2_AUTH_MD5: SetStringProperty(kEapPhase2AuthProperty, is_peap ? kEapPhase2AuthPEAPMD5 - : kEapPhase2AuthTTLSMD5); + : kEapPhase2AuthTTLSMD5, + NULL); break; case EAP_PHASE_2_AUTH_MSCHAPV2: SetStringProperty(kEapPhase2AuthProperty, is_peap ? kEapPhase2AuthPEAPMSCHAPV2 - : kEapPhase2AuthTTLSMSCHAPV2); + : kEapPhase2AuthTTLSMSCHAPV2, + NULL); break; case EAP_PHASE_2_AUTH_MSCHAP: - SetStringProperty(kEapPhase2AuthProperty, kEapPhase2AuthTTLSMSCHAP); + SetStringProperty(kEapPhase2AuthProperty, kEapPhase2AuthTTLSMSCHAP, NULL); break; case EAP_PHASE_2_AUTH_PAP: - SetStringProperty(kEapPhase2AuthProperty, kEapPhase2AuthTTLSPAP); + SetStringProperty(kEapPhase2AuthProperty, kEapPhase2AuthTTLSPAP, NULL); break; case EAP_PHASE_2_AUTH_CHAP: - SetStringProperty(kEapPhase2AuthProperty, kEapPhase2AuthTTLSCHAP); + SetStringProperty(kEapPhase2AuthProperty, kEapPhase2AuthTTLSCHAP, NULL); break; } } @@ -1616,34 +1767,32 @@ void WifiNetwork::SetEAPPhase2Auth(EAPPhase2Auth auth) { void WifiNetwork::SetEAPServerCaCertNssNickname( const std::string& nss_nickname) { VLOG(1) << "SetEAPServerCaCertNssNickname " << nss_nickname; - eap_server_ca_cert_nss_nickname_ = nss_nickname; - SetOrClearStringProperty(kEapCaCertNssProperty, nss_nickname); + SetOrClearStringProperty(kEapCaCertNssProperty, nss_nickname, + &eap_server_ca_cert_nss_nickname_); } void WifiNetwork::SetEAPClientCertPkcs11Id(const std::string& pkcs11_id) { VLOG(1) << "SetEAPClientCertPkcs11Id " << pkcs11_id; - eap_client_cert_pkcs11_id_ = pkcs11_id; - SetOrClearStringProperty(kEapCertIDProperty, pkcs11_id); + SetOrClearStringProperty(kEapCertIDProperty, pkcs11_id, + &eap_client_cert_pkcs11_id_); } void WifiNetwork::SetEAPUseSystemCAs(bool use_system_cas) { - eap_use_system_cas_ = use_system_cas; - SetBooleanProperty(kEapUseSystemCAsProperty, use_system_cas); + SetBooleanProperty(kEapUseSystemCAsProperty, use_system_cas, + &eap_use_system_cas_); } void WifiNetwork::SetEAPIdentity(const std::string& identity) { - eap_identity_ = identity; - SetOrClearStringProperty(kEapIdentityProperty, identity); + SetOrClearStringProperty(kEapIdentityProperty, identity, &eap_identity_); } void WifiNetwork::SetEAPAnonymousIdentity(const std::string& identity) { - eap_anonymous_identity_ = identity; - SetOrClearStringProperty(kEapAnonymousIdentityProperty, identity); + SetOrClearStringProperty(kEapAnonymousIdentityProperty, identity, + &eap_anonymous_identity_); } void WifiNetwork::SetEAPPassphrase(const std::string& passphrase) { - eap_passphrase_ = passphrase; - SetOrClearStringProperty(kEapPasswordProperty, passphrase); + SetOrClearStringProperty(kEapPasswordProperty, passphrase, &eap_passphrase_); } std::string WifiNetwork::GetEncryptionString() const { @@ -1923,10 +2072,10 @@ class NetworkLibraryImpl : public NetworkLibrary { const std::string& IPAddress() const { // Returns IP address for the active network. + // TODO(stevenjb): Fix this for VPNs. See chromium-os:13972. const Network* result = active_network(); - if (active_virtual_ && active_virtual_->is_active() && - (!result || active_virtual_->priority_ > result->priority_)) - result = active_virtual_; + if (!result) + result = connected_network(); // happens if we are connected to a VPN. if (!result) result = ethernet_; // Use non active ethernet addr if no active network. if (result) @@ -2001,6 +2150,14 @@ class NetworkLibraryImpl : public NetworkLibrary { return NULL; } + virtual VirtualNetwork* FindVirtualNetworkByPath( + const std::string& path) const { + Network* network = FindNetworkByPath(path); + if (network && network->type() == TYPE_VPN) + return static_cast<VirtualNetwork*>(network); + return NULL; + } + virtual const CellularDataPlanVector* GetDataPlans( const std::string& path) const { CellularDataPlanMap::const_iterator iter = data_plan_map_.find(path); @@ -2124,74 +2281,77 @@ class NetworkLibraryImpl : public NetworkLibrary { return true; } - static void WirelessConnectCallback(void *object, - const char *path, - NetworkMethodErrorType error, - const char* error_message) { + static void NetworkConnectCallback(void *object, + const char *path, + NetworkMethodErrorType error, + const char* error_message) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); - WirelessNetwork* wireless = networklib->FindWirelessNetworkByPath(path); - if (!wireless) { - LOG(ERROR) << "No wireless network for path: " << path; + Network* network = networklib->FindNetworkByPath(path); + if (!network) { + LOG(ERROR) << "No network for path: " << path; return; } if (error != NETWORK_METHOD_ERROR_NONE) { + LOG(WARNING) << "Error from ServiceConnect callback for: " + << network->name() + << " Error: " << error << " Message: " << error_message; if (error_message && strcmp(error_message, kErrorPassphraseRequiredMsg) == 0) { // This will trigger the connection failed notification. // TODO(stevenjb): Remove if chromium-os:13203 gets fixed. - wireless->set_state(STATE_FAILURE); - wireless->set_error(ERROR_BAD_PASSPHRASE); + network->set_state(STATE_FAILURE); + network->set_error(ERROR_BAD_PASSPHRASE); networklib->NotifyNetworkManagerChanged(true); // Forced update. - } else { - LOG(WARNING) << "Error from ServiceConnect callback: " - << error_message; } return; } + VLOG(1) << "Connected to service: " << network->name(); + // Update local cache and notify listeners. - if (wireless->type() == TYPE_WIFI) { - WifiNetwork* wifi = static_cast<WifiNetwork *>(wireless); + if (network->type() == TYPE_WIFI) { + WifiNetwork* wifi = static_cast<WifiNetwork *>(network); // If the user asked not to save credentials, flimflam will have // forgotten them. Wipe our cache as well. if (!wifi->save_credentials()) { wifi->EraseCredentials(); } networklib->active_wifi_ = wifi; - } else if (wireless->type() == TYPE_CELLULAR) { - networklib->active_cellular_ = static_cast<CellularNetwork *>(wireless); + } else if (network->type() == TYPE_CELLULAR) { + networklib->active_cellular_ = static_cast<CellularNetwork *>(network); + } else if (network->type() == TYPE_VPN) { + networklib->active_virtual_ = static_cast<VirtualNetwork *>(network); } else { - LOG(ERROR) << "Network of unexpected type: " << wireless->type(); + LOG(ERROR) << "Network of unexpected type: " << network->type(); } // If we succeed, this network will be remembered; request an update. // TODO(stevenjb): flimflam should do this automatically. networklib->RequestRememberedNetworksUpdate(); // Notify observers. - networklib->NotifyNetworkManagerChanged(false); // Not forced. - networklib->NotifyUserConnectionInitiated(wireless); + networklib->NotifyNetworkManagerChanged(true); // Forced update. + networklib->NotifyUserConnectionInitiated(network); } - void CallConnectToNetworkForWifi(WifiNetwork* wifi) { - // If we haven't correctly set the parameters (e.g. passphrase), flimflam - // might fail without attempting a connection. In order to trigger any - // notifications, set the state locally and notify observers. - // TODO(stevenjb): Remove if chromium-os:13203 gets fixed. - wifi->set_connecting(true); + void CallConnectToNetwork(Network* network) { + // In order to be certain to trigger any notifications, set the connecting + // state locally and notify observers. Otherwise there might be a state + // change without a forced notify. + network->set_connecting(true); NotifyNetworkManagerChanged(true); // Forced update. - RequestNetworkServiceConnect(wifi->service_path().c_str(), - WirelessConnectCallback, this); + RequestNetworkServiceConnect(network->service_path().c_str(), + NetworkConnectCallback, this); } virtual void ConnectToWifiNetwork(WifiNetwork* wifi) { DCHECK(wifi); if (!EnsureCrosLoaded() || !wifi) return; - CallConnectToNetworkForWifi(wifi); + CallConnectToNetwork(wifi); } // Use this to connect to a wifi network by service path. @@ -2204,7 +2364,7 @@ class NetworkLibraryImpl : public NetworkLibrary { << service_path; return; } - CallConnectToNetworkForWifi(wifi); + CallConnectToNetwork(wifi); } // Use this to connect to an unlisted wifi network. @@ -2214,16 +2374,20 @@ class NetworkLibraryImpl : public NetworkLibrary { const std::string& ssid, const std::string& passphrase, const std::string& identity, - const std::string& certpath, - bool auto_connect) { + const std::string& certpath) { if (!EnsureCrosLoaded()) return; + // Store the connection data to be used by the callback. + connect_data_.service_name = ssid; + connect_data_.passphrase = passphrase; + connect_data_.identity = identity; + connect_data_.cert_path = certpath; + // Asynchronously request service properties and call + // WifiServiceUpdateAndConnect. RequestHiddenWifiNetwork(ssid.c_str(), SecurityToString(security), WifiServiceUpdateAndConnect, this); - // Store the connection data to be used by the callback. - connect_data_.SetData(ssid, passphrase, identity, certpath, auto_connect); } // Callback @@ -2237,38 +2401,33 @@ class NetworkLibraryImpl : public NetworkLibrary { const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); Network* network = networklib->ParseNetwork(std::string(service_path), dict); - // Blocking DBus call. TODO(stevenjb): make async. - networklib->ConnectToNetworkUsingConnectData(network); + DCHECK(network->type() == TYPE_WIFI); + networklib->ConnectToWifiNetworkUsingConnectData( + static_cast<WifiNetwork*>(network)); } } - void ConnectToNetworkUsingConnectData(Network* network) { + void ConnectToWifiNetworkUsingConnectData(WifiNetwork* wifi) { ConnectData& data = connect_data_; - if (network->name() != data.name) { - LOG(WARNING) << "Network name does not match ConnectData: " - << network->name() << " != " << data.name; + if (wifi->name() != data.service_name) { + LOG(WARNING) << "Wifi network name does not match ConnectData: " + << wifi->name() << " != " << data.service_name; return; } + wifi->set_added(true); + wifi->SetIdentity(data.identity); + wifi->SetPassphrase(data.passphrase); + if (!data.cert_path.empty()) + wifi->SetCertPath(data.cert_path); - WifiNetwork *wifi = static_cast<WifiNetwork *>(network); - if (!data.passphrase.empty()) - wifi->SetPassphrase(data.passphrase); - if (!data.identity.empty()) - wifi->SetIdentity(data.identity); - if (!data.certpath.empty()) - wifi->SetCertPath(data.certpath); - wifi->SetAutoConnect(data.auto_connect); - - CallConnectToNetworkForWifi(wifi); + CallConnectToNetwork(wifi); } virtual void ConnectToCellularNetwork(CellularNetwork* network) { DCHECK(network); if (!EnsureCrosLoaded() || !network) return; - - RequestNetworkServiceConnect(network->service_path().c_str(), - WirelessConnectCallback, this); + CallConnectToNetwork(network); } // Records information that cellular play payment had happened. @@ -2283,22 +2442,92 @@ class NetworkLibraryImpl : public NetworkLibrary { cellular_plan_payment_time_).InHours() < kRecentPlanPaymentHours; } - virtual void DisconnectFromWirelessNetwork(const WirelessNetwork* network) { + virtual void ConnectToVirtualNetwork(VirtualNetwork* network) { + DCHECK(network); + if (!EnsureCrosLoaded() || !network) + return; + CallConnectToNetwork(network); + } + + virtual void ConnectToVirtualNetworkPSK( + const std::string& service_name, + const std::string& server, + const std::string& psk, + const std::string& username, + const std::string& user_passphrase) { + if (!EnsureCrosLoaded()) + return; + // Store the connection data to be used by the callback. + connect_data_.service_name = service_name; + connect_data_.psk_key = psk; + connect_data_.server_hostname = server; + connect_data_.identity = username; + connect_data_.passphrase = user_passphrase; + RequestVirtualNetwork(service_name.c_str(), + server.c_str(), + kProviderL2tpIpsec, + VPNServiceUpdateAndConnect, + this); + } + + // Callback + static void VPNServiceUpdateAndConnect(void* object, + const char* service_path, + const Value* info) { + NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); + DCHECK(networklib); + if (service_path && info) { + VLOG(1) << "Connecting to new VPN Service: " << service_path; + DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); + const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); + Network* network = + networklib->ParseNetwork(std::string(service_path), dict); + DCHECK(network->type() == TYPE_VPN); + networklib->ConnectToVirtualNetworkUsingConnectData( + static_cast<VirtualNetwork*>(network)); + } else { + LOG(WARNING) << "Unable to create VPN Service: " << service_path; + } + } + + void ConnectToVirtualNetworkUsingConnectData(VirtualNetwork* vpn) { + ConnectData& data = connect_data_; + if (vpn->name() != data.service_name) { + LOG(WARNING) << "Virtual network name does not match ConnectData: " + << vpn->name() << " != " << data.service_name; + return; + } + + vpn->set_added(true); + vpn->set_server_hostname(data.server_hostname); + vpn->SetCACert(""); + vpn->SetUserCert(""); + vpn->SetUserCertKey(""); + vpn->SetPSKPassphrase(data.psk_key); + vpn->SetUsername(data.identity); + vpn->SetUserPassphrase(data.passphrase); + + CallConnectToNetwork(vpn); + } + + virtual void DisconnectFromNetwork(const Network* network) { DCHECK(network); if (!EnsureCrosLoaded() || !network) return; - if (DisconnectFromNetwork(network->service_path().c_str())) { + VLOG(1) << "Disconnect from network: " << network->service_path(); + if (chromeos::DisconnectFromNetwork(network->service_path().c_str())) { // Update local cache and notify listeners. - WirelessNetwork* wireless = - FindWirelessNetworkByPath(network->service_path()); - if (wireless) { - wireless->set_connected(false); - if (wireless == active_wifi_) + Network* found_network = FindNetworkByPath(network->service_path()); + if (found_network) { + found_network->set_connected(false); + if (found_network == active_wifi_) active_wifi_ = NULL; - else if (wireless == active_cellular_) + else if (found_network == active_cellular_) active_cellular_ = NULL; + else if (found_network == active_virtual_) + active_virtual_ = NULL; } - NotifyNetworkManagerChanged(false); // Not forced. + NotifyNetworkManagerChanged(true); // Forced update. } } @@ -2313,7 +2542,7 @@ class NetworkLibraryImpl : public NetworkLibrary { // https://crosbug.com/9295 if (DeleteRememberedService(service_path.c_str())) { DeleteRememberedNetwork(service_path); - NotifyNetworkManagerChanged(false); // Not forced. + NotifyNetworkManagerChanged(true); // Forced update. } } @@ -2350,11 +2579,30 @@ class NetworkLibraryImpl : public NetworkLibrary { Network* result = NULL; if (ethernet_ && ethernet_->is_active()) result = ethernet_; - if (active_wifi_ && active_wifi_->is_active() && - (!result || active_wifi_->priority_ > result->priority_)) + if ((active_wifi_ && active_wifi_->is_active()) && + (!result || + active_wifi_->priority_order_ < result->priority_order_)) + result = active_wifi_; + if ((active_cellular_ && active_cellular_->is_active()) && + (!result || + active_cellular_->priority_order_ < result->priority_order_)) + result = active_cellular_; + return result; + } + + virtual const Network* connected_network() const { + // Use flimflam's ordering of the services to determine what the connected + // network is (i.e. don't assume priority of network types). + Network* result = NULL; + if (ethernet_ && ethernet_->connected()) + result = ethernet_; + if ((active_wifi_ && active_wifi_->connected()) && + (!result || + active_wifi_->priority_order_ < result->priority_order_)) result = active_wifi_; - if (active_cellular_ && active_cellular_->is_active() && - (!result || active_cellular_->priority_ > result->priority_)) + if ((active_cellular_ && active_cellular_->connected()) && + (!result || + active_cellular_->priority_order_ < result->priority_order_)) result = active_cellular_; return result; } @@ -2419,62 +2667,6 @@ class NetworkLibraryImpl : public NetworkLibrary { return ipconfig_vector; } - virtual std::string GetHtmlInfo(int refresh) { - std::string output; - output.append("<html><head><title>About Network</title>"); - if (refresh > 0) - output.append("<meta http-equiv=\"refresh\" content=\"" + - base::IntToString(refresh) + "\"/>"); - output.append("</head><body>"); - if (refresh > 0) { - output.append("(Auto-refreshing page every " + - base::IntToString(refresh) + "s)"); - } else { - output.append("(To auto-refresh this page: about:network/<secs>)"); - } - - if (ethernet_enabled()) { - output.append("<h3>Ethernet:</h3><table border=1>"); - if (ethernet_) { - output.append("<tr>" + ToHtmlTableHeader(ethernet_) + "</tr>"); - output.append("<tr>" + ToHtmlTableRow(ethernet_) + "</tr>"); - } - } - - if (wifi_enabled()) { - output.append("</table><h3>Wifi:</h3><table border=1>"); - for (size_t i = 0; i < wifi_networks_.size(); ++i) { - if (i == 0) - output.append("<tr>" + ToHtmlTableHeader(wifi_networks_[i]) + - "</tr>"); - output.append("<tr>" + ToHtmlTableRow(wifi_networks_[i]) + "</tr>"); - } - } - - if (cellular_enabled()) { - output.append("</table><h3>Cellular:</h3><table border=1>"); - for (size_t i = 0; i < cellular_networks_.size(); ++i) { - if (i == 0) - output.append("<tr>" + ToHtmlTableHeader(cellular_networks_[i]) + - "</tr>"); - output.append("<tr>" + ToHtmlTableRow(cellular_networks_[i]) + "</tr>"); - } - } - - output.append("</table><h3>Remembered Wifi:</h3><table border=1>"); - for (size_t i = 0; i < remembered_wifi_networks_.size(); ++i) { - if (i == 0) - output.append( - "<tr>" + ToHtmlTableHeader(remembered_wifi_networks_[i]) + - "</tr>"); - output.append("<tr>" + ToHtmlTableRow(remembered_wifi_networks_[i]) + - "</tr>"); - } - - output.append("</table></body></html>"); - return output; - } - private: typedef std::map<std::string, Network*> NetworkMap; @@ -2633,10 +2825,13 @@ class NetworkLibraryImpl : public NetworkLibrary { static void NetworkManagerUpdate(void* object, const char* manager_path, const Value* info) { - VLOG(1) << "Received NetworkManagerUpdate."; NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); - DCHECK(info); + if (!info) { + LOG(ERROR) << "Error retrieving manager properties: " << manager_path; + return; + } + VLOG(1) << "Received NetworkManagerUpdate."; DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); networklib->ParseNetworkManager(dict); @@ -2658,7 +2853,11 @@ class NetworkLibraryImpl : public NetworkLibrary { const Value* info) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); - DCHECK(info); + if (!info) { + LOG(ERROR) << "Error retrieving profile: " << profile_path; + return; + } + VLOG(1) << "Received ProfileUpdate for: " << profile_path; DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); ListValue* entries(NULL); @@ -2921,7 +3120,7 @@ class NetworkLibraryImpl : public NetworkLibrary { NetworkMap old_network_map = network_map_; ClearNetworks(false /*don't delete*/); // Clear the list of update requests. - int network_priority = 0; + int network_priority_order = 0; network_update_requests_.clear(); // wifi_scanning_ will remain false unless we request a network update. wifi_scanning_ = false; @@ -2944,7 +3143,7 @@ class NetworkLibraryImpl : public NetworkLibrary { // rely on watched network updates and only request updates here for // new networks. // Use update_request map to store network priority. - network_update_requests_[service_path] = network_priority++; + network_update_requests_[service_path] = network_priority_order++; wifi_scanning_ = true; RequestNetworkServiceInfo(service_path.c_str(), &NetworkServiceUpdate, @@ -3057,7 +3256,7 @@ class NetworkLibraryImpl : public NetworkLibrary { // Find and erase entry in update_requests, and set network priority. PriorityMap::iterator found2 = network_update_requests_.find(service_path); if (found2 != network_update_requests_.end()) { - network->priority_ = found2->second; + network->priority_order_ = found2->second; network_update_requests_.erase(found2); if (network_update_requests_.empty()) { // Clear wifi_scanning_ when we have no pending requests. @@ -3069,7 +3268,7 @@ class NetworkLibraryImpl : public NetworkLibrary { // << service_path; } - VLOG(1) << "ParseNetwork:" << network->name(); + VLOG(1) << "ParseNetwork: " << network->name(); NotifyNetworkManagerChanged(false); // Not forced. return network; } @@ -3086,7 +3285,7 @@ class NetworkLibraryImpl : public NetworkLibrary { AddRememberedNetwork(network); } network->ParseInfo(info); // virtual. - VLOG(1) << "ParseRememberedNetwork:" << network->name(); + VLOG(1) << "ParseRememberedNetwork: " << network->name(); NotifyNetworkManagerChanged(false); // Not forced. return network; } @@ -3235,6 +3434,7 @@ class NetworkLibraryImpl : public NetworkLibrary { } void NotifyNetworkChanged(Network* network) { + VLOG(2) << "Network changed: " << network->name(); DCHECK(network); NetworkObserverMap::const_iterator iter = network_observers_.find( network->service_path()); @@ -3316,7 +3516,7 @@ class NetworkLibraryImpl : public NetworkLibrary { return; Network* network = FindNetworkByPath(path); if (network) { - VLOG(1) << "UpdateNetworkStatus: " << network->name() << "." << key; + VLOG(2) << "UpdateNetworkStatus: " << network->name() << "." << key; // Note: ParseValue is virtual. int index = property_index_parser().Get(std::string(key)); if (!network->ParseValue(index, value)) { @@ -3448,6 +3648,7 @@ class NetworkLibraryImpl : public NetworkLibrary { wifi1->set_name("Fake Wifi Connected"); wifi1->set_strength(90); wifi1->set_connected(true); + wifi1->set_active(true); wifi1->set_encryption(SECURITY_NONE); AddNetwork(wifi1); @@ -3481,7 +3682,8 @@ class NetworkLibraryImpl : public NetworkLibrary { CellularNetwork* cellular1 = new CellularNetwork("fc1"); cellular1->set_name("Fake Cellular"); cellular1->set_strength(70); - cellular1->set_connected(false); + cellular1->set_connected(true); + cellular1->set_active(true); cellular1->set_activation_state(ACTIVATION_STATE_ACTIVATED); cellular1->set_payment_url(std::string("http://www.google.com")); cellular1->set_usage_url(std::string("http://www.google.com")); @@ -3524,6 +3726,32 @@ class NetworkLibraryImpl : public NetworkLibrary { remembered_wifi2->set_encryption(SECURITY_WEP); AddRememberedNetwork(remembered_wifi2); + // VPNs. + VirtualNetwork* vpn1 = new VirtualNetwork("fv1"); + vpn1->set_name("Fake VPN Provider 1"); + vpn1->set_server_hostname("vpn1server.fake.com"); + vpn1->set_provider_type(VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK); + vpn1->set_username("VPN User 1"); + vpn1->set_connected(false); + AddNetwork(vpn1); + + VirtualNetwork* vpn2 = new VirtualNetwork("fv2"); + vpn2->set_name("Fake VPN Provider 2"); + vpn2->set_server_hostname("vpn2server.fake.com"); + vpn2->set_provider_type(VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT); + vpn2->set_username("VPN User 2"); + vpn2->set_connected(true); + AddNetwork(vpn2); + + VirtualNetwork* vpn3 = new VirtualNetwork("fv3"); + vpn3->set_name("Fake VPN Provider 3"); + vpn3->set_server_hostname("vpn3server.fake.com"); + vpn3->set_provider_type(VirtualNetwork::PROVIDER_TYPE_OPEN_VPN); + vpn3->set_connected(false); + AddNetwork(vpn3); + + active_virtual_ = vpn2; + wifi_scanning_ = false; offline_mode_ = false; } @@ -3623,23 +3851,12 @@ class NetworkLibraryImpl : public NetworkLibrary { // Temporary connection data for async connect calls. struct ConnectData { - ConnectData() : auto_connect(false) {} - void SetData(const std::string& n, - const std::string& p, - const std::string& id, - const std::string& cert, - bool autocon) { - name = n; - passphrase = p; - identity = id; - certpath = cert; - auto_connect = autocon; - } - std::string name; + std::string service_name; std::string passphrase; std::string identity; - std::string certpath; - bool auto_connect; + std::string cert_path; + std::string psk_key; + std::string server_hostname; }; ConnectData connect_data_; @@ -3733,6 +3950,8 @@ class NetworkLibraryStubImpl : public NetworkLibrary { const std::string& path) const { return NULL; } virtual CellularNetwork* FindCellularNetworkByPath( const std::string& path) const { return NULL; } + virtual VirtualNetwork* FindVirtualNetworkByPath( + const std::string& path) const { return NULL; } virtual const CellularDataPlanVector* GetDataPlans( const std::string& path) const { return NULL; } virtual const CellularDataPlan* GetSignificantDataPlan( @@ -3755,12 +3974,18 @@ class NetworkLibraryStubImpl : public NetworkLibrary { const std::string& ssid, const std::string& passphrase, const std::string& identity, - const std::string& certpath, - bool auto_connect) {} + const std::string& certpath) {} virtual void ConnectToCellularNetwork(CellularNetwork* network) {} + virtual void ConnectToVirtualNetwork(VirtualNetwork* network) {} + virtual void ConnectToVirtualNetworkPSK( + const std::string& service_name, + const std::string& server, + const std::string& psk, + const std::string& username, + const std::string& user_passphrase) {} virtual void SignalCellularPlanPayment() {} virtual bool HasRecentCellularPlanPayment() { return false; } - virtual void DisconnectFromWirelessNetwork(const WirelessNetwork* network) {} + virtual void DisconnectFromNetwork(const Network* network) {} virtual void ForgetWifiNetwork(const std::string& service_path) {} virtual bool ethernet_available() const { return true; } virtual bool wifi_available() const { return false; } @@ -3770,6 +3995,7 @@ class NetworkLibraryStubImpl : public NetworkLibrary { virtual bool cellular_enabled() const { return false; } virtual bool wifi_scanning() const { return false; } virtual const Network* active_network() const { return NULL; } + virtual const Network* connected_network() const { return NULL; } virtual bool offline_mode() const { return false; } virtual void EnableEthernetNetworkDevice(bool enable) {} virtual void EnableWifiNetworkDevice(bool enable) {} @@ -3780,7 +4006,6 @@ class NetworkLibraryStubImpl : public NetworkLibrary { hardware_address->clear(); return NetworkIPConfigVector(); } - virtual std::string GetHtmlInfo(int refresh) { return std::string(); } private: std::string ip_address_; diff --git a/chrome/browser/chromeos/cros/network_library.h b/chrome/browser/chromeos/cros/network_library.h index 41411a0..e80a810 100644 --- a/chrome/browser/chromeos/cros/network_library.h +++ b/chrome/browser/chromeos/cros/network_library.h @@ -227,9 +227,7 @@ class Network { ConnectionType type() const { return type_; } ConnectionMode mode() const { return mode_; } ConnectionState connection_state() const { return state_; } - bool connecting() const { return state_ == STATE_ASSOCIATION || - state_ == STATE_CONFIGURATION || - state_ == STATE_CARRIER; } + bool connecting() const { return IsConnectingState(state_); } bool configuring() const { return state_ == STATE_CONFIGURATION; } bool connected() const { return state_ == STATE_READY; } bool connecting_or_connected() const { return connecting() || connected(); } @@ -249,6 +247,7 @@ class Network { bool favorite() const { return favorite_; } bool auto_connect() const { return auto_connect_; } ConnectivityState connectivity_state() const { return connectivity_state_; } + bool added() const { return added_; } // We don't have a setter for |favorite_| because to unfavorite a network is // equivalent to forget a network, so we call forget network on cros for @@ -261,6 +260,12 @@ class Network { // Return a string representation of the error code. std::string GetErrorString() const; + static bool IsConnectingState(ConnectionState state) { + return (state == STATE_ASSOCIATION || + state == STATE_CONFIGURATION || + state == STATE_CARRIER); + } + protected: Network(const std::string& service_path, ConnectionType type) : state_(STATE_UNKNOWN), @@ -270,23 +275,27 @@ class Network { favorite_(false), auto_connect_(false), connectivity_state_(CONN_STATE_UNKNOWN), - priority_(0), + priority_order_(0), + added_(false), service_path_(service_path), type_(type) {} // Parse name/value pairs from libcros. virtual bool ParseValue(int index, const Value* value); - void ParseInfo(const DictionaryValue* info); + virtual void ParseInfo(const DictionaryValue* info); // Methods to asynchronously set network service properties - virtual void SetStringProperty(const char* prop, const std::string& str); - virtual void SetBooleanProperty(const char* prop, bool b); - virtual void SetIntegerProperty(const char* prop, int i); + virtual void SetStringProperty(const char* prop, const std::string& str, + std::string* dest); + virtual void SetBooleanProperty(const char* prop, bool b, bool* dest); + virtual void SetIntegerProperty(const char* prop, int i, int* dest); virtual void SetValueProperty(const char* prop, Value* val); virtual void ClearProperty(const char* prop); + // This will clear the property if string is empty. Otherwise, it will set it. virtual void SetOrClearStringProperty(const char* prop, - const std::string& str); + const std::string& str, + std::string* dest); std::string device_path_; std::string name_; @@ -315,12 +324,16 @@ class Network { void set_connectivity_state(ConnectivityState connectivity_state) { connectivity_state_ = connectivity_state; } + void set_added(bool added) { added_ = added; } // Initialize the IP address field void InitIPAddress(); - // Priority value, corresponds to index in list from flimflam (0 = highest) - int priority_; + // Priority value, corresponds to index in list from flimflam (0 = first) + int priority_order_; + + // Set to true if the UI requested this as a new network. + bool added_; // These must not be modified after construction. std::string service_path_; @@ -328,6 +341,7 @@ class Network { friend class NetworkLibraryImpl; friend class NetworkLibraryStubImpl; + DISALLOW_COPY_AND_ASSIGN(Network); // ChangeAutoConnectSaveTest accesses |favorite_|. FRIEND_TEST_ALL_PREFIXES(WifiConfigViewTest, ChangeAutoConnectSaveTest); }; @@ -338,14 +352,92 @@ class EthernetNetwork : public Network { explicit EthernetNetwork(const std::string& service_path) : Network(service_path, TYPE_ETHERNET) { } + private: + friend class NetworkLibraryImpl; + DISALLOW_COPY_AND_ASSIGN(EthernetNetwork); }; // Class for networks of TYPE_VPN. class VirtualNetwork : public Network { public: + enum ProviderType { + PROVIDER_TYPE_L2TP_IPSEC_PSK, + PROVIDER_TYPE_L2TP_IPSEC_USER_CERT, + PROVIDER_TYPE_OPEN_VPN, + // Add new provider types before PROVIDER_TYPE_MAX. + PROVIDER_TYPE_MAX, + }; + explicit VirtualNetwork(const std::string& service_path) : - Network(service_path, TYPE_VPN) { + Network(service_path, TYPE_VPN), + provider_type_(PROVIDER_TYPE_L2TP_IPSEC_PSK) { } + + const std::string& server_hostname() const { return server_hostname_; } + ProviderType provider_type() const { return provider_type_; } + const std::string& ca_cert() const { return ca_cert_; } + const std::string& psk_passphrase() const { return psk_passphrase_; } + const std::string& user_cert() const { return user_cert_; } + const std::string& user_cert_key() const { return user_cert_key_; } + const std::string& username() const { return username_; } + const std::string& user_passphrase() const { return user_passphrase_; } + + bool NeedMoreInfoToConnect() const; + + // Public setters. + void SetCACert(const std::string& ca_cert); + void SetPSKPassphrase(const std::string& psk_passphrase); + void SetUserCert(const std::string& user_cert); + void SetUserCertKey(const std::string& key); + void SetUsername(const std::string& username); + void SetUserPassphrase(const std::string& user_passphrase); + + std::string GetProviderTypeString() const; + + private: + // Network overrides. + virtual bool ParseValue(int index, const Value* value); + virtual void ParseInfo(const DictionaryValue* info); + + // VirtualNetwork private methods. + bool ParseProviderValue(int index, const Value* value); + + void set_server_hostname(const std::string& server_hostname) { + server_hostname_ = server_hostname; + } + void set_provider_type(ProviderType provider_type) { + provider_type_ = provider_type; + } + void set_ca_cert(const std::string& ca_cert) { + ca_cert_ = ca_cert; + } + void set_psk_passphrase(const std::string& psk_passphrase) { + psk_passphrase_ = psk_passphrase; + } + void set_user_cert(const std::string& user_cert) { + user_cert_ = user_cert; + } + void set_user_cert_key(const std::string& key) { + user_cert_key_ = key; + } + void set_username(const std::string& username) { + username_ = username; + } + void set_user_passphrase(const std::string& user_passphrase) { + user_passphrase_ = user_passphrase; + } + + std::string server_hostname_; + ProviderType provider_type_; + std::string ca_cert_; + std::string psk_passphrase_; + std::string user_cert_; + std::string user_cert_key_; + std::string username_; + std::string user_passphrase_; + + friend class NetworkLibraryImpl; + DISALLOW_COPY_AND_ASSIGN(VirtualNetwork); }; typedef std::vector<VirtualNetwork*> VirtualNetworkVector; @@ -368,6 +460,7 @@ class WirelessNetwork : public Network { friend class NetworkLibraryImpl; friend class NetworkLibraryStubImpl; + DISALLOW_COPY_AND_ASSIGN(WirelessNetwork); }; // Class for networks of TYPE_CELLULAR. @@ -490,6 +583,7 @@ class CellularNetwork : public WirelessNetwork { friend class NetworkLibraryImpl; friend class NetworkLibraryStubImpl; + DISALLOW_COPY_AND_ASSIGN(CellularNetwork); }; typedef std::vector<CellularNetwork*> CellularNetworkVector; @@ -598,6 +692,7 @@ class WifiNetwork : public WirelessNetwork { std::string user_passphrase_; friend class NetworkLibraryImpl; + DISALLOW_COPY_AND_ASSIGN(WifiNetwork); }; typedef std::vector<WifiNetwork*> WifiNetworkVector; @@ -854,6 +949,8 @@ class NetworkLibrary { virtual WifiNetwork* FindWifiNetworkByPath(const std::string& path) const = 0; virtual CellularNetwork* FindCellularNetworkByPath( const std::string& path) const = 0; + virtual VirtualNetwork* FindVirtualNetworkByPath( + const std::string& path) const = 0; // Retrieves the data plans associated with |path|, NULL if there are no // associated plans. @@ -903,13 +1000,13 @@ class NetworkLibrary { // Same as above but searches for an existing network by name. virtual void ConnectToWifiNetwork(const std::string& service_path) = 0; - // Connect to the specified network with security, ssid, and passphrase. + // Connect to the specified network with security, ssid, passphrase, identity, + // and (optionally) certpath. virtual void ConnectToWifiNetwork(ConnectionSecurity security, const std::string& ssid, const std::string& passphrase, const std::string& identity, - const std::string& certpath, - bool auto_connect) = 0; + const std::string& certpath) = 0; // Connect to the specified cellular network. virtual void ConnectToCellularNetwork(CellularNetwork* network) = 0; @@ -920,9 +1017,20 @@ class NetworkLibrary { // Returns true if cellular plan payment had been recorded recently. virtual bool HasRecentCellularPlanPayment() = 0; - // Disconnect from the specified wireless (either cellular or wifi) network. - virtual void DisconnectFromWirelessNetwork( - const WirelessNetwork* network) = 0; + // Connect to the specified virtual network. + virtual void ConnectToVirtualNetwork(VirtualNetwork* network) = 0; + + // Connect to the specified virtual network with service name, + // server hostname, provider_type, PSK passphrase, username and passphrase. + virtual void ConnectToVirtualNetworkPSK( + const std::string& service_name, + const std::string& server_hostname, + const std::string& psk, + const std::string& username, + const std::string& user_passphrase) = 0; + + // Disconnect from the specified network. + virtual void DisconnectFromNetwork(const Network* network) = 0; // Forget the wifi network corresponding to service_path. virtual void ForgetWifiNetwork(const std::string& service_path) = 0; @@ -938,6 +1046,7 @@ class NetworkLibrary { virtual bool wifi_scanning() const = 0; virtual const Network* active_network() const = 0; + virtual const Network* connected_network() const = 0; virtual bool offline_mode() const = 0; @@ -961,10 +1070,6 @@ class NetworkLibrary { const std::string& device_path, std::string* hardware_address) = 0; - // Fetches debug network info for display in about:network. - // The page will have a meta refresh of |refresh| seconds if |refresh| > 0. - virtual std::string GetHtmlInfo(int refresh) = 0; - // Factory function, creates a new instance and returns ownership. // For normal usage, access the singleton via CrosLibrary::Get(). static NetworkLibrary* GetImpl(bool stub); diff --git a/chrome/browser/chromeos/network_login_observer.cc b/chrome/browser/chromeos/network_login_observer.cc index 09e1a8e..9fa09d0 100644 --- a/chrome/browser/chromeos/network_login_observer.cc +++ b/chrome/browser/chromeos/network_login_observer.cc @@ -19,7 +19,8 @@ namespace chromeos { NetworkLoginObserver::NetworkLoginObserver(NetworkLibrary* netlib) { - RefreshStoredNetworks(netlib->wifi_networks()); + RefreshStoredNetworks(netlib->wifi_networks(), + netlib->virtual_networks()); netlib->AddNetworkManagerObserver(this); } @@ -49,39 +50,49 @@ void NetworkLoginObserver::CreateModalPopup(views::WindowDelegate* view) { } void NetworkLoginObserver::RefreshStoredNetworks( - const WifiNetworkVector& wifi_networks) { - wifi_network_failures_.clear(); + const WifiNetworkVector& wifi_networks, + const VirtualNetworkVector& virtual_networks) { + network_failures_.clear(); for (WifiNetworkVector::const_iterator it = wifi_networks.begin(); - it < wifi_networks.end(); it++) { + it != wifi_networks.end(); it++) { const WifiNetwork* wifi = *it; - wifi_network_failures_[wifi->service_path()] = wifi->failed(); + network_failures_[wifi->service_path()] = wifi->failed(); + } + for (VirtualNetworkVector::const_iterator it = virtual_networks.begin(); + it != virtual_networks.end(); it++) { + const VirtualNetwork* vpn = *it; + network_failures_[vpn->service_path()] = vpn->failed(); } } void NetworkLoginObserver::OnNetworkManagerChanged(NetworkLibrary* cros) { const WifiNetworkVector& wifi_networks = cros->wifi_networks(); + const VirtualNetworkVector& virtual_networks = cros->virtual_networks(); NetworkConfigView* view = NULL; // Check to see if we have any newly failed wifi network. for (WifiNetworkVector::const_iterator it = wifi_networks.begin(); - it < wifi_networks.end(); it++) { + it != wifi_networks.end(); it++) { WifiNetwork* wifi = *it; if (wifi->failed()) { - WifiFailureMap::iterator iter = - wifi_network_failures_.find(wifi->service_path()); + NetworkFailureMap::iterator iter = + network_failures_.find(wifi->service_path()); // If the network did not previously exist, then don't do anything. // For example, if the user travels to a location and finds a service // that has previously failed, we don't want to show an error. - if (iter == wifi_network_failures_.end()) + if (iter == network_failures_.end()) continue; // If this network was in a failed state previously, then it's not new. if (iter->second) continue; - // Display login box again for bad_passphrase and bad_wepkey errors. + // Display login dialog again for bad_passphrase and bad_wepkey errors. + // Always re-display the login dialog for added networks that failed to + // connect for any reason (e.g. incorrect security type was chosen). if (wifi->error() == ERROR_BAD_PASSPHRASE || - wifi->error() == ERROR_BAD_WEPKEY) { + wifi->error() == ERROR_BAD_WEPKEY || + wifi->added()) { // The NetworkConfigView will show the appropriate error message. view = new NetworkConfigView(wifi); // There should only be one wifi network that failed to connect. @@ -91,8 +102,28 @@ void NetworkLoginObserver::OnNetworkManagerChanged(NetworkLibrary* cros) { } } } + // Check to see if we have any newly failed virtual network. + // See wifi section for detailed comments. + if (!view) { + for (VirtualNetworkVector::const_iterator it = virtual_networks.begin(); + it != virtual_networks.end(); it++) { + VirtualNetwork* vpn = *it; + if (vpn->failed()) { + NetworkFailureMap::iterator iter = + network_failures_.find(vpn->service_path()); + if (iter == network_failures_.end()) + continue; // New network. + if (iter->second) + continue; // Previous failure. + if (vpn->error() == ERROR_BAD_PASSPHRASE || vpn->added()) { + view = new NetworkConfigView(vpn); + break; + } + } + } + } - RefreshStoredNetworks(wifi_networks); + RefreshStoredNetworks(wifi_networks, virtual_networks); // Show login box if necessary. if (view) diff --git a/chrome/browser/chromeos/network_login_observer.h b/chrome/browser/chromeos/network_login_observer.h index 0c5df5f..34970aa 100644 --- a/chrome/browser/chromeos/network_login_observer.h +++ b/chrome/browser/chromeos/network_login_observer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -25,17 +25,18 @@ class NetworkLoginObserver : public NetworkLibrary::NetworkManagerObserver { explicit NetworkLoginObserver(NetworkLibrary* netlib); virtual ~NetworkLoginObserver(); - typedef std::map<std::string, bool> WifiFailureMap; + typedef std::map<std::string, bool> NetworkFailureMap; private: virtual void CreateModalPopup(views::WindowDelegate* view); - virtual void RefreshStoredNetworks(const WifiNetworkVector& wifi_networks); + virtual void RefreshStoredNetworks(const WifiNetworkVector& wifi_networks, + const VirtualNetworkVector& vpn_networks); // NetworkLibrary::NetworkManagerObserver implementation. virtual void OnNetworkManagerChanged(NetworkLibrary* obj); // Wifi networks by service path mapped to if it failed previously. - WifiFailureMap wifi_network_failures_; + NetworkFailureMap network_failures_; DISALLOW_COPY_AND_ASSIGN(NetworkLoginObserver); }; diff --git a/chrome/browser/chromeos/network_message_observer.cc b/chrome/browser/chromeos/network_message_observer.cc index ece96d6..477c307 100644 --- a/chrome/browser/chromeos/network_message_observer.cc +++ b/chrome/browser/chromeos/network_message_observer.cc @@ -62,8 +62,6 @@ NetworkMessageObserver::~NetworkMessageObserver() { notification_connection_error_.Hide(); notification_low_data_.Hide(); notification_no_data_.Hide(); - STLDeleteValues(&cellular_networks_); - STLDeleteValues(&wifi_networks_); } // static @@ -162,63 +160,83 @@ void NetworkMessageObserver::ShowLowDataNotification( false, false); } -void NetworkMessageObserver::OnNetworkManagerChanged(NetworkLibrary* obj) { - const WifiNetworkVector& wifi_networks = obj->wifi_networks(); - const CellularNetworkVector& cellular_networks = obj->cellular_networks(); - - std::string new_failed_network; - // Check to see if we have any newly failed wifi network. - for (WifiNetworkVector::const_iterator it = wifi_networks.begin(); - it < wifi_networks.end(); it++) { - const WifiNetwork* wifi = *it; - if (wifi->failed()) { - ServicePathWifiMap::iterator iter = - wifi_networks_.find(wifi->service_path()); - // If the network did not previously exist, then don't do anything. - // For example, if the user travels to a location and finds a service - // that has previously failed, we don't want to show a notification. - if (iter == wifi_networks_.end()) - continue; - - const WifiNetwork* wifi_old = iter->second; - // If network connection failed, display a notification. - // We only do this if we were trying to make a new connection. - // So if a previously connected network got disconnected for any reason, - // we don't display notification. - if (wifi_old->connecting()) { - new_failed_network = wifi->name(); - // Like above, there should only be one newly failed network. - break; - } +bool NetworkMessageObserver::CheckNetworkFailed(const Network* network) { + if (network->failed()) { + NetworkStateMap::iterator iter = + network_states_.find(network->service_path()); + // If the network did not previously exist, then don't do anything. + // For example, if the user travels to a location and finds a service + // that has previously failed, we don't want to show a notification. + if (iter == network_states_.end()) + return false; + // If network connection failed, display a notification. + // We only do this if we were trying to make a new connection. + // So if a previously connected network got disconnected for any reason, + // we don't display notification. + ConnectionState prev_state = iter->second; + if (Network::IsConnectingState(prev_state)) + return true; + } + return false; +} + +void NetworkMessageObserver::OnNetworkManagerChanged(NetworkLibrary* cros) { + const Network* new_failed_network = NULL; + // Check to see if we have any newly failed networks. + for (WifiNetworkVector::const_iterator it = cros->wifi_networks().begin(); + it != cros->wifi_networks().end(); it++) { + const WifiNetwork* net = *it; + if (CheckNetworkFailed(net)) { + new_failed_network = net; + break; // There should only be one failed network. } } - // Refresh stored networks. - STLDeleteValues(&wifi_networks_); - wifi_networks_.clear(); - for (WifiNetworkVector::const_iterator it = wifi_networks.begin(); - it < wifi_networks.end(); it++) { - const WifiNetwork* wifi = *it; - wifi_networks_[wifi->service_path()] = new WifiNetwork(*wifi); + if (!new_failed_network) { + for (CellularNetworkVector::const_iterator it = + cros->cellular_networks().begin(); + it != cros->cellular_networks().end(); it++) { + const CellularNetwork* net = *it; + if (CheckNetworkFailed(net)) { + new_failed_network = net; + break; // There should only be one failed network. + } + } } - STLDeleteValues(&cellular_networks_); - cellular_networks_.clear(); - for (CellularNetworkVector::const_iterator it = cellular_networks.begin(); - it < cellular_networks.end(); it++) { - const CellularNetwork* cellular = *it; - cellular_networks_[cellular->service_path()] = - new CellularNetwork(*cellular); + if (!new_failed_network) { + for (VirtualNetworkVector::const_iterator it = + cros->virtual_networks().begin(); + it != cros->virtual_networks().end(); it++) { + const VirtualNetwork* net = *it; + if (CheckNetworkFailed(net)) { + new_failed_network = net; + break; // There should only be one failed network. + } + } } + network_states_.clear(); + for (WifiNetworkVector::const_iterator it = cros->wifi_networks().begin(); + it != cros->wifi_networks().end(); it++) + network_states_[(*it)->service_path()] = (*it)->state(); + for (CellularNetworkVector::const_iterator it = + cros->cellular_networks().begin(); + it != cros->cellular_networks().end(); it++) + network_states_[(*it)->service_path()] = (*it)->state(); + for (VirtualNetworkVector::const_iterator it = + cros->virtual_networks().begin(); + it != cros->virtual_networks().end(); it++) + network_states_[(*it)->service_path()] = (*it)->state(); + // Show connection error notification if necessary. - if (!new_failed_network.empty()) { + if (new_failed_network) { // Hide if already shown to force show it in case user has closed it. if (notification_connection_error_.visible()) notification_connection_error_.Hide(); notification_connection_error_.Show(l10n_util::GetStringFUTF16( IDS_NETWORK_CONNECTION_ERROR_MESSAGE, - ASCIIToUTF16(new_failed_network)), false, false); + ASCIIToUTF16(new_failed_network->name())), false, false); } } @@ -279,7 +297,7 @@ void NetworkMessageObserver::OnCellularDataPlanChanged(NetworkLibrary* cros) { cellular_data_plan_type_ = current_plan->plan_type; } -void NetworkMessageObserver::OnConnectionInitiated(NetworkLibrary* obj, +void NetworkMessageObserver::OnConnectionInitiated(NetworkLibrary* cros, const Network* network) { // If user initiated any network connection, we hide the error notification. notification_connection_error_.Hide(); diff --git a/chrome/browser/chromeos/network_message_observer.h b/chrome/browser/chromeos/network_message_observer.h index 9fe263c..78112d5 100644 --- a/chrome/browser/chromeos/network_message_observer.h +++ b/chrome/browser/chromeos/network_message_observer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -27,8 +27,6 @@ class NetworkMessageObserver : public NetworkLibrary::NetworkManagerObserver, explicit NetworkMessageObserver(Profile* profile); virtual ~NetworkMessageObserver(); - typedef std::map<std::string, WifiNetwork*> ServicePathWifiMap; - typedef std::map<std::string, CellularNetwork*> ServicePathCellularMap; static bool IsApplicableBackupPlan(const CellularDataPlan* plan, const CellularDataPlan* other_plan); private: @@ -38,6 +36,7 @@ class NetworkMessageObserver : public NetworkLibrary::NetworkManagerObserver, virtual void ShowNeedsPlanNotification(const CellularNetwork* cellular); virtual void ShowNoDataNotification(CellularDataPlanType plan_type); virtual void ShowLowDataNotification(const CellularDataPlan* plan); + virtual bool CheckNetworkFailed(const Network* network); // NetworkLibrary::NetworkManagerObserver implementation. virtual void OnNetworkManagerChanged(NetworkLibrary* obj); @@ -47,10 +46,10 @@ class NetworkMessageObserver : public NetworkLibrary::NetworkManagerObserver, virtual void OnConnectionInitiated(NetworkLibrary* obj, const Network* network); - // Wifi networks by service path. - ServicePathWifiMap wifi_networks_; - // Cellular networks by service path. - ServicePathCellularMap cellular_networks_; + typedef std::map<std::string, ConnectionState> NetworkStateMap; + + // Network state by service path. + NetworkStateMap network_states_; // Current connect celluar service path. std::string cellular_service_path_; diff --git a/chrome/browser/chromeos/options/network_config_view.cc b/chrome/browser/chromeos/options/network_config_view.cc index 8b4f9f0..39afba8 100644 --- a/chrome/browser/chromeos/options/network_config_view.cc +++ b/chrome/browser/chromeos/options/network_config_view.cc @@ -8,6 +8,7 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/chromeos/options/vpn_config_view.h" #include "chrome/browser/chromeos/options/wifi_config_view.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" @@ -23,20 +24,35 @@ using views::WidgetGtk; namespace chromeos { -NetworkConfigView::NetworkConfigView(WifiNetwork* wifi) +// static +const int ChildNetworkConfigView::kPassphraseWidth = 150; + +NetworkConfigView::NetworkConfigView(Network* network) : browser_mode_(true), - title_(UTF16ToWide( - l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_JOIN_WIFI_NETWORKS))), - wificonfig_view_(new WifiConfigView(this, wifi)), delegate_(NULL) { + if (network->type() == TYPE_WIFI) { + child_config_view_ = + new WifiConfigView(this, static_cast<WifiNetwork*>(network)); + } else if (network->type() == TYPE_VPN) { + child_config_view_ = + new VPNConfigView(this, static_cast<VirtualNetwork*>(network)); + } else { + NOTREACHED(); + child_config_view_ = NULL; + } } -NetworkConfigView::NetworkConfigView() +NetworkConfigView::NetworkConfigView(ConnectionType type) : browser_mode_(true), - title_(UTF16ToWide( - l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_JOIN_WIFI_NETWORKS))), - wificonfig_view_(new WifiConfigView(this)), delegate_(NULL) { + if (type == TYPE_WIFI) { + child_config_view_ = new WifiConfigView(this); + } else if (type == TYPE_VPN) { + child_config_view_ = new VPNConfigView(this); + } else { + NOTREACHED(); + child_config_view_ = NULL; + } } gfx::NativeWindow NetworkConfigView::GetNativeWindow() const { @@ -55,26 +71,26 @@ bool NetworkConfigView::IsDialogButtonEnabled( MessageBoxFlags::DialogButton button) const { // Disable connect button if cannot login. if (button == MessageBoxFlags::DIALOGBUTTON_OK) - return wificonfig_view_->CanLogin(); + return child_config_view_->CanLogin(); return true; } bool NetworkConfigView::Cancel() { if (delegate_) delegate_->OnDialogCancelled(); - wificonfig_view_->Cancel(); + child_config_view_->Cancel(); return true; } bool NetworkConfigView::Accept() { - bool result = wificonfig_view_->Login(); + bool result = child_config_view_->Login(); if (result && delegate_) delegate_->OnDialogAccepted(); return result; } std::wstring NetworkConfigView::GetWindowTitle() const { - return title_; + return UTF16ToWide(child_config_view_->GetTitle()); } void NetworkConfigView::GetAccessibleState(ui::AccessibleViewState* state) { @@ -84,14 +100,17 @@ void NetworkConfigView::GetAccessibleState(ui::AccessibleViewState* state) { } void NetworkConfigView::Layout() { - wificonfig_view_->SetBounds(0, 0, width(), height()); + child_config_view_->SetBounds(0, 0, width(), height()); } gfx::Size NetworkConfigView::GetPreferredSize() { gfx::Size result(views::Window::GetLocalizedContentsSize( IDS_JOIN_WIFI_NETWORK_DIALOG_WIDTH_CHARS, IDS_JOIN_WIFI_NETWORK_DIALOG_MINIMUM_HEIGHT_LINES)); - result.set_height(wificonfig_view_->GetPreferredSize().height()); + gfx::Size size = child_config_view_->GetPreferredSize(); + result.set_height(size.height()); + if (size.width() > result.width()) + result.set_width(size.width()); return result; } @@ -100,7 +119,7 @@ void NetworkConfigView::ViewHierarchyChanged( // Can't init before we're inserted into a Container, because we require // a HWND to parent native child controls to. if (is_add && child == this) - AddChildView(wificonfig_view_); + AddChildView(child_config_view_); } } // namespace chromeos diff --git a/chrome/browser/chromeos/options/network_config_view.h b/chrome/browser/chromeos/options/network_config_view.h index d3de6bb..02e4762 100644 --- a/chrome/browser/chromeos/options/network_config_view.h +++ b/chrome/browser/chromeos/options/network_config_view.h @@ -16,7 +16,7 @@ class Window; namespace chromeos { -class WifiConfigView; +class ChildNetworkConfigView; // A dialog box for showing a password textfield. class NetworkConfigView : public views::View, @@ -34,10 +34,10 @@ class NetworkConfigView : public views::View, virtual ~Delegate() {} }; - // Login dialog for wifi. - explicit NetworkConfigView(WifiNetwork* wifi); - // Login dialog for hidden networks. - explicit NetworkConfigView(); + // Login dialog for known networks. + explicit NetworkConfigView(Network* network); + // Login dialog for new/hidden networks. + explicit NetworkConfigView(ConnectionType type); virtual ~NetworkConfigView() {} // Returns corresponding native window. @@ -83,17 +83,50 @@ class NetworkConfigView : public views::View, // True when opening in browser, otherwise in OOBE/login mode. bool browser_mode_; - std::wstring title_; - - // WifiConfig is the only child of this class. - // It will get deleted when NetworkConfigView gets cleaned up. - WifiConfigView* wificonfig_view_; + // There's always only one child view, which will get deleted when + // NetworkConfigView gets cleaned up. + ChildNetworkConfigView* child_config_view_; Delegate* delegate_; DISALLOW_COPY_AND_ASSIGN(NetworkConfigView); }; +// Children of NetworkConfigView must subclass this and implement the virtual +// methods, which are called by NetworkConfigView. +class ChildNetworkConfigView : public views::View { + public: + // Called to get title for parent NetworkConfigView dialog box. + virtual string16 GetTitle() = 0; + + // Called to determine if "Connect" button should be enabled. + virtual bool CanLogin() = 0; + + // Called when "Connect" button is clicked. + // Should return false if dialog should remain open. + virtual bool Login() = 0; + + // Called when "Cancel" button is clicked. + virtual void Cancel() = 0; + + // Width of passphrase fields. + static const int kPassphraseWidth; + + protected: + explicit ChildNetworkConfigView(NetworkConfigView* parent, Network* network) + : service_path_(network->service_path()), + parent_(parent) {} + explicit ChildNetworkConfigView(NetworkConfigView* parent) + : parent_(parent) {} + virtual ~ChildNetworkConfigView() {} + + std::string service_path_; + NetworkConfigView* parent_; + + private: + DISALLOW_COPY_AND_ASSIGN(ChildNetworkConfigView); +}; + } // namespace chromeos #endif // CHROME_BROWSER_CHROMEOS_OPTIONS_NETWORK_CONFIG_VIEW_H_ diff --git a/chrome/browser/chromeos/options/vpn_config_view.cc b/chrome/browser/chromeos/options/vpn_config_view.cc new file mode 100644 index 0000000..d1456dc --- /dev/null +++ b/chrome/browser/chromeos/options/vpn_config_view.cc @@ -0,0 +1,443 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/options/vpn_config_view.h" + +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "views/controls/button/image_button.h" +#include "views/controls/button/native_button.h" +#include "views/controls/label.h" +#include "views/controls/textfield/textfield.h" +#include "views/layout/grid_layout.h" +#include "views/layout/layout_constants.h" +#include "views/window/window.h" + +namespace { + +string16 ProviderTypeToString(chromeos::VirtualNetwork::ProviderType type) { + switch (type) { + case chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: + return l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_PSK); + case chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: + return l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_USER_CERT); + case chromeos::VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: + return l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_OPEN_VPN); + case chromeos::VirtualNetwork::PROVIDER_TYPE_MAX: + break; + } + NOTREACHED(); + return string16(); +} + +} // namespace + +namespace chromeos { + +int VPNConfigView::ProviderTypeComboboxModel::GetItemCount() { + // TODO(stevenjb): Include OpenVPN option once enabled. + return VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT + 1; + // return VirtualNetwork::PROVIDER_TYPE_MAX; +} + +string16 VPNConfigView::ProviderTypeComboboxModel::GetItemAt(int index) { + VirtualNetwork::ProviderType type = + static_cast<VirtualNetwork::ProviderType>(index); + return ProviderTypeToString(type); +} + +VPNConfigView::UserCertComboboxModel::UserCertComboboxModel() { + // TODO(jamescook): populate user_certs_. chromium-os:14111 +} + +int VPNConfigView::UserCertComboboxModel::GetItemCount() { + return static_cast<int>(user_certs_.size()); +} + +string16 VPNConfigView::UserCertComboboxModel::GetItemAt(int index) { + if (index >= 0 && index < static_cast<int>(user_certs_.size())) + return ASCIIToUTF16(user_certs_[index]); + return string16(); +} + +VPNConfigView::VPNConfigView(NetworkConfigView* parent, VirtualNetwork* vpn) + : ChildNetworkConfigView(parent, vpn) { + Init(vpn); +} + +VPNConfigView::VPNConfigView(NetworkConfigView* parent) + : ChildNetworkConfigView(parent) { + Init(NULL); +} + +VPNConfigView::~VPNConfigView() { +} + +void VPNConfigView::UpdateCanLogin() { + parent_->GetDialogClientView()->UpdateDialogButtons(); +} + +string16 VPNConfigView::GetTitle() { + return l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_ADD_VPN); +} + +bool VPNConfigView::CanLogin() { + static const size_t kMinPassphraseLen = 0; // TODO(stevenjb): min length? + if (service_path_.empty() && + (GetService().empty() || GetServer().empty())) + return false; + if (provider_type_ == VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK && + psk_passphrase_textfield_->text().length() < kMinPassphraseLen) + return false; + if (GetUsername().empty()) + return false; + if (user_passphrase_textfield_->text().length() < kMinPassphraseLen) + return false; + return true; +} + +void VPNConfigView::UpdateErrorLabel() { + std::string error_msg; + if (!service_path_.empty()) { + // TODO(kuan): differentiate between bad psk and user passphrases. + NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); + VirtualNetwork* vpn = cros->FindVirtualNetworkByPath(service_path_); + if (vpn && vpn->failed()) { + if (vpn->error() == ERROR_BAD_PASSPHRASE) { + error_msg = l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE); + } else { + error_msg = vpn->GetErrorString(); + } + } + } + if (!error_msg.empty()) { + error_label_->SetText(UTF8ToWide(error_msg)); + error_label_->SetVisible(true); + } else { + error_label_->SetVisible(false); + } +} + +void VPNConfigView::ContentsChanged(views::Textfield* sender, + const string16& new_contents) { + if (sender == server_textfield_ && !service_text_modified_) { + // Set the service name to the server name up to '.', unless it has + // been explicityly set by the user. + string16 server = server_textfield_->text(); + string16::size_type n = server.find_first_of(L'.'); + service_name_from_server_ = server.substr(0, n); + service_textfield_->SetText(service_name_from_server_); + } + if (sender == service_textfield_) { + if (new_contents.empty()) + service_text_modified_ = false; + else if (new_contents != service_name_from_server_) + service_text_modified_ = true; + } + UpdateCanLogin(); +} + +bool VPNConfigView::HandleKeyEvent(views::Textfield* sender, + const views::KeyEvent& key_event) { + if ((sender == psk_passphrase_textfield_ || + sender == user_passphrase_textfield_) && + key_event.key_code() == ui::VKEY_RETURN) { + parent_->GetDialogClientView()->AcceptWindow(); + } + return false; +} + +void VPNConfigView::ButtonPressed(views::Button* sender, + const views::Event& event) { +} + +void VPNConfigView::ItemChanged(views::Combobox* combo_box, + int prev_index, int new_index) { + if (prev_index == new_index) + return; + if (combo_box == provider_type_combobox_) { + provider_type_ = static_cast<VirtualNetwork::ProviderType>(new_index); + EnableControls(); + } else if (combo_box == user_cert_combobox_) { + // Nothing to do for now. + } else { + NOTREACHED(); + } + UpdateCanLogin(); +} + +bool VPNConfigView::Login() { + NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); + if (service_path_.empty()) { + switch (provider_type_) { + case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: + cros->ConnectToVirtualNetworkPSK(GetService(), + GetServer(), + GetPSKPassphrase(), + GetUsername(), + GetUserPassphrase()); + break; + case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: + case VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: + // TODO(stevenjb): Add support for OpenVPN and user certs. + LOG(WARNING) << "Unsupported provider type: " << provider_type_; + break; + case VirtualNetwork::PROVIDER_TYPE_MAX: + break; + } + } else { + VirtualNetwork* vpn = cros->FindVirtualNetworkByPath(service_path_); + if (!vpn) { + // TODO(stevenjb): Add notification for this. + LOG(WARNING) << "VPN no longer exists: " << service_path_; + return true; // Close dialog. + } + switch (provider_type_) { + case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: + vpn->SetPSKPassphrase(GetPSKPassphrase()); + break; + case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: + case VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: { + const std::string user_cert = UTF16ToUTF8( + user_cert_combobox_->model()->GetItemAt( + user_cert_combobox_->selected_item())); + vpn->SetUserCert(user_cert); + break; + } + case VirtualNetwork::PROVIDER_TYPE_MAX: + break; + } + vpn->SetUsername(GetUsername()); + vpn->SetUserPassphrase(GetUserPassphrase()); + + cros->ConnectToVirtualNetwork(vpn); + } + // Connection failures are responsible for updating the UI, including + // reopening dialogs. + return true; // Close dialog. +} + +void VPNConfigView::Cancel() { +} + +const std::string VPNConfigView::GetTextFromField( + views::Textfield* textfield, bool trim_whitespace) const { + std::string untrimmed = UTF16ToUTF8(textfield->text()); + if (!trim_whitespace) + return untrimmed; + std::string result; + TrimWhitespaceASCII(untrimmed, TRIM_ALL, &result); + return result; +} + +const std::string VPNConfigView::GetService() const { + if (service_textfield_ != NULL) + return GetTextFromField(service_textfield_, true); + return service_path_; +} + +const std::string VPNConfigView::GetServer() const { + if (server_textfield_ != NULL) + return GetTextFromField(server_textfield_, true); + return server_hostname_; +} + +const std::string VPNConfigView::GetPSKPassphrase() const { + if (psk_passphrase_textfield_->IsEnabled() && + psk_passphrase_textfield_->IsVisible()) + return GetTextFromField(psk_passphrase_textfield_, false); + return std::string(); +} + +const std::string VPNConfigView::GetUsername() const { + return GetTextFromField(username_textfield_, true); +} + +const std::string VPNConfigView::GetUserPassphrase() const { + return GetTextFromField(user_passphrase_textfield_, false); +} + +void VPNConfigView::Init(VirtualNetwork* vpn) { + views::GridLayout* layout = views::GridLayout::CreatePanel(this); + SetLayoutManager(layout); + + int column_view_set_id = 0; + views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id); + // Label. + column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1, + views::GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing); + // Textfield, combobox. + column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, + views::GridLayout::USE_PREF, 0, + ChildNetworkConfigView::kPassphraseWidth); + column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing); + // Passphrase visible button. + column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 1, + views::GridLayout::USE_PREF, 0, 0); + + // Initialize members. + service_text_modified_ = false; + provider_type_ = vpn ? + vpn->provider_type() : + chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK; + + // Server label and input. + layout->StartRow(0, column_view_set_id); + layout->AddView(new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME)))); + if (!vpn) { + server_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); + server_textfield_->SetController(this); + layout->AddView(server_textfield_); + server_text_ = NULL; + } else { + server_hostname_ = vpn->server_hostname(); + server_text_ = new views::Label(ASCIIToWide(server_hostname_)); + server_text_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + layout->AddView(server_text_); + server_textfield_ = NULL; + } + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // Service label and name or input. + layout->StartRow(0, column_view_set_id); + layout->AddView(new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME)))); + if (!vpn) { + service_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); + service_textfield_->SetController(this); + layout->AddView(service_textfield_); + service_text_ = NULL; + } else { + service_text_ = new views::Label(ASCIIToWide(vpn->name())); + service_text_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + layout->AddView(service_text_); + service_textfield_ = NULL; + } + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // Provider type label and select. + layout->StartRow(0, column_view_set_id); + layout->AddView(new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE)))); + if (!vpn) { + provider_type_combobox_ = + new views::Combobox(new ProviderTypeComboboxModel()); + provider_type_combobox_->set_listener(this); + layout->AddView(provider_type_combobox_); + provider_type_text_label_ = NULL; + } else { + provider_type_text_label_ = + new views::Label(UTF16ToWide(ProviderTypeToString(provider_type_))); + layout->AddView(provider_type_text_label_); + provider_type_combobox_ = NULL; + } + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // PSK passphrase label, input and visible button. + layout->StartRow(0, column_view_set_id); + psk_passphrase_label_ = new views::Label(UTF16ToWide( + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PSK_PASSPHRASE))); + layout->AddView(psk_passphrase_label_); + psk_passphrase_textfield_ = new views::Textfield( + views::Textfield::STYLE_PASSWORD); + psk_passphrase_textfield_->SetController(this); + if (vpn && !vpn->psk_passphrase().empty()) + psk_passphrase_textfield_->SetText(UTF8ToUTF16(vpn->psk_passphrase())); + layout->AddView(psk_passphrase_textfield_); + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // User certificate label and input. + layout->StartRow(0, column_view_set_id); + user_cert_label_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_CERT))); + layout->AddView(user_cert_label_); + user_cert_combobox_ = new views::Combobox(new UserCertComboboxModel()); + user_cert_combobox_->set_listener(this); + if (vpn && !vpn->user_cert().empty()) { + string16 user_cert = UTF8ToUTF16(vpn->user_cert()); + for (int i = 0; i < user_cert_combobox_->model()->GetItemCount(); ++i) { + if (user_cert_combobox_->model()->GetItemAt(i) == user_cert) { + user_cert_combobox_->SetSelectedItem(i); + break; + } + } + } + layout->AddView(user_cert_combobox_); + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // Username label and input. + layout->StartRow(0, column_view_set_id); + layout->AddView(new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME)))); + username_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); + username_textfield_->SetController(this); + if (vpn && !vpn->username().empty()) + username_textfield_->SetText(UTF8ToUTF16(vpn->username())); + layout->AddView(username_textfield_); + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // User passphrase label, input and visble button. + layout->StartRow(0, column_view_set_id); + layout->AddView(new views::Label(UTF16ToWide( + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_PASSPHRASE)))); + user_passphrase_textfield_ = new views::Textfield( + views::Textfield::STYLE_PASSWORD); + user_passphrase_textfield_->SetController(this); + if (vpn && !vpn->user_passphrase().empty()) + user_passphrase_textfield_->SetText(UTF8ToUTF16(vpn->user_passphrase())); + layout->AddView(user_passphrase_textfield_); + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // Error label. + layout->StartRow(0, column_view_set_id); + layout->SkipColumns(1); + error_label_ = new views::Label(); + error_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + error_label_->SetColor(SK_ColorRED); + layout->AddView(error_label_); + + // Enable controls based on provider type combo. + EnableControls(); + + // Set or hide the error text. + UpdateErrorLabel(); +} + +void VPNConfigView::EnableControls() { + switch (provider_type_) { + case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: + psk_passphrase_label_->SetEnabled(true); + psk_passphrase_textfield_->SetEnabled(true); + user_cert_label_->SetEnabled(false); + user_cert_combobox_->SetEnabled(false); + break; + case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: + case VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: + psk_passphrase_label_->SetEnabled(false); + psk_passphrase_textfield_->SetEnabled(false); + user_cert_label_->SetEnabled(true); + user_cert_combobox_->SetEnabled(true); + break; + default: + NOTREACHED(); + } +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/options/vpn_config_view.h b/chrome/browser/chromeos/options/vpn_config_view.h new file mode 100644 index 0000000..17a81de --- /dev/null +++ b/chrome/browser/chromeos/options/vpn_config_view.h @@ -0,0 +1,125 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_VPN_CONFIG_VIEW_H_ +#define CHROME_BROWSER_CHROMEOS_OPTIONS_VPN_CONFIG_VIEW_H_ +#pragma once + +#include <string> + +#include "base/string16.h" +#include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/options/network_config_view.h" +#include "chrome/browser/ui/shell_dialogs.h" +#include "ui/base/models/combobox_model.h" +#include "views/controls/button/button.h" +#include "views/controls/button/native_button.h" +#include "views/controls/combobox/combobox.h" +#include "views/controls/textfield/textfield_controller.h" +#include "views/view.h" + +namespace views { +class Label; +} + +namespace chromeos { + +// A dialog box to allow configuration of VPN connection. +class VPNConfigView : public ChildNetworkConfigView, + public views::TextfieldController, + public views::ButtonListener, + public views::Combobox::Listener { + public: + VPNConfigView(NetworkConfigView* parent, VirtualNetwork* vpn); + explicit VPNConfigView(NetworkConfigView* parent); + virtual ~VPNConfigView(); + + // views::TextfieldController methods. + virtual void ContentsChanged(views::Textfield* sender, + const string16& new_contents); + virtual bool HandleKeyEvent(views::Textfield* sender, + const views::KeyEvent& key_event); + + // views::ButtonListener + virtual void ButtonPressed(views::Button* sender, const views::Event& event); + + // views::Combobox::Listener + virtual void ItemChanged(views::Combobox* combo_box, + int prev_index, int new_index); + + // ChildNetworkConfigView implementation. + virtual string16 GetTitle() OVERRIDE; + virtual bool CanLogin() OVERRIDE; + virtual bool Login() OVERRIDE; + virtual void Cancel() OVERRIDE; + + private: + class ProviderTypeComboboxModel : public ui::ComboboxModel { + public: + ProviderTypeComboboxModel() {} + virtual ~ProviderTypeComboboxModel() {} + virtual int GetItemCount(); + virtual string16 GetItemAt(int index); + private: + DISALLOW_COPY_AND_ASSIGN(ProviderTypeComboboxModel); + }; + + class UserCertComboboxModel : public ui::ComboboxModel { + public: + UserCertComboboxModel(); + virtual ~UserCertComboboxModel() {} + virtual int GetItemCount(); + virtual string16 GetItemAt(int index); + private: + std::vector<std::string> user_certs_; + DISALLOW_COPY_AND_ASSIGN(UserCertComboboxModel); + }; + + // Initializes data members and create UI controls. + void Init(VirtualNetwork* vpn); + + void EnableControls(); + + // Update state of the Login button. + void UpdateCanLogin(); + + // Update the error text label. + void UpdateErrorLabel(); + + // Get text from input field. + const std::string GetTextFromField(views::Textfield* textfield, + bool trim_whitespace) const; + + // Convenience methods to get text from input field or cached VirtualNetwork. + const std::string GetService() const; + const std::string GetServer() const; + const std::string GetPSKPassphrase() const; + const std::string GetUsername() const; + const std::string GetUserPassphrase() const; + + std::string server_hostname_; + string16 service_name_from_server_; + bool service_text_modified_; + VirtualNetwork::ProviderType provider_type_; + + views::Label* service_text_; + views::Textfield* service_textfield_; + views::Label* server_text_; + views::Textfield* server_textfield_; + views::Combobox* provider_type_combobox_; + views::Label* provider_type_text_label_; + views::Label* psk_passphrase_label_; + views::Textfield* psk_passphrase_textfield_; + views::Label* user_cert_label_; + views::Combobox* user_cert_combobox_; + views::Textfield* username_textfield_; + views::Textfield* user_passphrase_textfield_; + views::Label* error_label_; + + DISALLOW_COPY_AND_ASSIGN(VPNConfigView); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_OPTIONS_VPN_CONFIG_VIEW_H_ diff --git a/chrome/browser/chromeos/options/wifi_config_view.cc b/chrome/browser/chromeos/options/wifi_config_view.cc index 70ccaa4..efed960 100644 --- a/chrome/browser/chromeos/options/wifi_config_view.cc +++ b/chrome/browser/chromeos/options/wifi_config_view.cc @@ -9,7 +9,6 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/login/user_manager.h" -#include "chrome/browser/chromeos/options/network_config_view.h" #include "chrome/browser/chromeos/options/wifi_config_model.h" #include "chrome/common/chrome_switches.h" // TODO(jamescook): Remove. #include "grit/chromium_strings.h" @@ -31,9 +30,6 @@ namespace chromeos { namespace { -// The width of the password field. -const int kPasswordWidth = 150; - enum SecurityComboboxIndex { SECURITY_INDEX_NONE = 0, SECURITY_INDEX_WEP = 1, @@ -240,10 +236,9 @@ class ClientCertComboboxModel : public ui::ComboboxModel { } // namespace WifiConfigView::WifiConfigView(NetworkConfigView* parent, WifiNetwork* wifi) - : parent_(parent), + : ChildNetworkConfigView(parent, wifi), wifi_config_model_(new WifiConfigModel()), is_8021x_(false), - service_path_(wifi->service_path()), ssid_textfield_(NULL), eap_method_combobox_(NULL), phase_2_auth_label_(NULL), @@ -266,7 +261,7 @@ WifiConfigView::WifiConfigView(NetworkConfigView* parent, WifiNetwork* wifi) } WifiConfigView::WifiConfigView(NetworkConfigView* parent) - : parent_(parent), + : ChildNetworkConfigView(parent), wifi_config_model_(new WifiConfigModel()), is_8021x_(false), ssid_textfield_(NULL), @@ -293,6 +288,10 @@ WifiConfigView::WifiConfigView(NetworkConfigView* parent) WifiConfigView::~WifiConfigView() { } +string16 WifiConfigView::GetTitle() { + return l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_JOIN_WIFI_NETWORKS); +} + bool WifiConfigView::CanLogin() { static const size_t kMinWirelessPasswordLen = 5; @@ -361,27 +360,25 @@ void WifiConfigView::RefreshEAPFields() { identity_anonymous_textfield_->SetText(string16()); } -void WifiConfigView::UpdateErrorLabel(bool failed) { - static const int kNoError = -1; - int id = kNoError; +void WifiConfigView::UpdateErrorLabel() { + std::string error_msg; if (!service_path_.empty()) { NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); const WifiNetwork* wifi = cros->FindWifiNetworkByPath(service_path_); - if (wifi) { - // Right now, only displaying bad_passphrase and bad_wepkey errors. - if (wifi->error() == ERROR_BAD_PASSPHRASE) - id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE; - else if (wifi->error() == ERROR_BAD_WEPKEY) - id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_WEPKEY; + if (wifi && wifi->failed()) { + if (wifi->error() == ERROR_BAD_PASSPHRASE) { + error_msg = l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE); + } else if (wifi->error() == ERROR_BAD_WEPKEY) { + error_msg = l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_WEPKEY); + } else { + error_msg = wifi->GetErrorString(); + } } } - if (id == kNoError && failed) { - // We don't know what the error was. For now assume bad identity or - // passphrase. See TODO comment in Login() and crosbug.com/9538. - id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_CREDENTIALS; - } - if (id != kNoError) { - error_label_->SetText(UTF16ToWide(l10n_util::GetStringUTF16(id))); + if (!error_msg.empty()) { + error_label_->SetText(UTF8ToWide(error_msg)); error_label_->SetVisible(true); } else { error_label_->SetVisible(false); @@ -452,7 +449,7 @@ bool WifiConfigView::Login() { break; } cros->ConnectToWifiNetwork( - sec, GetSSID(), GetPassphrase(), std::string(), std::string(), true); + sec, GetSSID(), GetPassphrase(), std::string(), std::string()); } else { WifiNetwork* wifi = cros->FindWifiNetworkByPath(service_path_); if (!wifi) { @@ -606,7 +603,8 @@ void WifiConfigView::Init(WifiNetwork* wifi) { views::GridLayout::USE_PREF, 0, 0); // Textfield column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, - views::GridLayout::USE_PREF, 0, kPasswordWidth); + views::GridLayout::USE_PREF, 0, + ChildNetworkConfigView::kPassphraseWidth); // Password visible button column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 1, views::GridLayout::USE_PREF, 0, 0); @@ -675,8 +673,8 @@ void WifiConfigView::Init(WifiNetwork* wifi) { IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA))); layout->AddView(server_ca_cert_label_); server_ca_cert_combobox_ = new ComboboxWithWidth( - new ServerCACertComboboxModel( - wifi_config_model_.get()), kPasswordWidth); + new ServerCACertComboboxModel(wifi_config_model_.get()), + ChildNetworkConfigView::kPassphraseWidth); server_ca_cert_label_->SetEnabled(false); server_ca_cert_combobox_->SetEnabled(false); server_ca_cert_combobox_->set_listener(this); @@ -888,7 +886,7 @@ void WifiConfigView::Init(WifiNetwork* wifi) { layout->AddView(error_label_); // Set or hide the error text. - UpdateErrorLabel(false); + UpdateErrorLabel(); } } // namespace chromeos diff --git a/chrome/browser/chromeos/options/wifi_config_view.h b/chrome/browser/chromeos/options/wifi_config_view.h index b80c0c1..2961879 100644 --- a/chrome/browser/chromeos/options/wifi_config_view.h +++ b/chrome/browser/chromeos/options/wifi_config_view.h @@ -12,6 +12,7 @@ #include "base/memory/scoped_ptr.h" #include "base/string16.h" #include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/options/network_config_view.h" #include "chrome/browser/ui/shell_dialogs.h" #include "ui/base/models/combobox_model.h" #include "views/controls/button/button.h" @@ -29,11 +30,10 @@ class FilePath; namespace chromeos { -class NetworkConfigView; class WifiConfigModel; // A dialog box for showing a password textfield. -class WifiConfigView : public views::View, +class WifiConfigView : public ChildNetworkConfigView, public views::TextfieldController, public views::ButtonListener, public views::Combobox::Listener { @@ -58,10 +58,12 @@ class WifiConfigView : public views::View, virtual void ItemChanged(views::Combobox* combo_box, int prev_index, int new_index); + // ChildNetworkConfigView implementation. + virtual string16 GetTitle(); + virtual bool CanLogin(); + // Login to network. Returns false if the dialog should remain open. virtual bool Login(); - - // Cancel the dialog. virtual void Cancel(); // Get the typed in ssid. @@ -69,9 +71,6 @@ class WifiConfigView : public views::View, // Get the typed in passphrase. std::string GetPassphrase() const; - // Returns whether or not we can login. - bool CanLogin(); - private: // Initializes UI. void Init(WifiNetwork* wifi); @@ -83,17 +82,13 @@ class WifiConfigView : public views::View, void RefreshEAPFields(); // Updates the error text label. - void UpdateErrorLabel(bool failed); - - NetworkConfigView* parent_; + void UpdateErrorLabel(); scoped_ptr<WifiConfigModel> wifi_config_model_; // Whether or not it is an 802.1x network. bool is_8021x_; - std::string service_path_; - views::Textfield* ssid_textfield_; views::Combobox* eap_method_combobox_; views::Label* phase_2_auth_label_; diff --git a/chrome/browser/chromeos/status/network_menu.cc b/chrome/browser/chromeos/status/network_menu.cc index 19ac0a8..cbe473c 100644 --- a/chrome/browser/chromeos/status/network_menu.cc +++ b/chrome/browser/chromeos/status/network_menu.cc @@ -7,6 +7,7 @@ #include <algorithm> #include "base/logging.h" +#include "base/command_line.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" #include "chrome/browser/chromeos/choose_mobile_network_dialog.h" @@ -16,6 +17,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/views/window.h" #include "chrome/common/url_constants.h" +#include "chrome/common/chrome_switches.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "net/base/escape.h" @@ -28,69 +30,46 @@ namespace chromeos { -//////////////////////////////////////////////////////////////////////////////// -// NetworkMenu +class MainMenuModel : public NetworkMenuModel { + public: + explicit MainMenuModel(NetworkMenu* owner); + virtual ~MainMenuModel() {} -// static -const int NetworkMenu::kNumBarsImages = 4; + // NetworkMenuModel implementation. + virtual void InitMenuItems(bool is_browser_mode, + bool should_open_button_options); -// NOTE: Use an array rather than just calculating a resource number to avoid -// creating implicit ordering dependencies on the resource values. -// static -const int NetworkMenu::kBarsImages[kNumBarsImages] = { - IDR_STATUSBAR_NETWORK_BARS1, - IDR_STATUSBAR_NETWORK_BARS2, - IDR_STATUSBAR_NETWORK_BARS3, - IDR_STATUSBAR_NETWORK_BARS4, -}; -// static -const int NetworkMenu::kBarsImagesBlack[kNumBarsImages] = { - IDR_STATUSBAR_NETWORK_BARS1_BLACK, - IDR_STATUSBAR_NETWORK_BARS2_BLACK, - IDR_STATUSBAR_NETWORK_BARS3_BLACK, - IDR_STATUSBAR_NETWORK_BARS4_BLACK, -}; -/* -// static -const int NetworkMenu::kBarsImagesLowData[kNumBarsImages] = { - IDR_STATUSBAR_NETWORK_BARS1_ORANGE, - IDR_STATUSBAR_NETWORK_BARS2_ORANGE, - IDR_STATUSBAR_NETWORK_BARS3_ORANGE, - IDR_STATUSBAR_NETWORK_BARS4_ORANGE, -}; -// static -const int NetworkMenu::kBarsImagesVLowData[kNumBarsImages] = { - IDR_STATUSBAR_NETWORK_BARS1_RED, - IDR_STATUSBAR_NETWORK_BARS2_RED, - IDR_STATUSBAR_NETWORK_BARS3_RED, - IDR_STATUSBAR_NETWORK_BARS4_RED, + private: + scoped_ptr<NetworkMenuModel> vpn_menu_model_; + + DISALLOW_COPY_AND_ASSIGN(MainMenuModel); }; -*/ -// static -const int NetworkMenu::kNumAnimatingImages = 10; +class VPNMenuModel : public NetworkMenuModel { + public: + explicit VPNMenuModel(NetworkMenu* owner); + virtual ~VPNMenuModel() {} -// static -SkBitmap NetworkMenu::kAnimatingImages[kNumAnimatingImages]; + // NetworkMenuModel implementation. + virtual void InitMenuItems(bool is_browser_mode, + bool should_open_button_options); -// static -SkBitmap NetworkMenu::kAnimatingImagesBlack[kNumAnimatingImages]; + static SkBitmap IconForDisplay(const Network* network); -NetworkMenu::NetworkMenu() - : min_width_(-1) { - network_menu_.reset(new views::Menu2(this)); -} + private: + DISALLOW_COPY_AND_ASSIGN(VPNMenuModel); +}; -NetworkMenu::~NetworkMenu() { -} +//////////////////////////////////////////////////////////////////////////////// +// NetworkMenuModel, public methods: -bool NetworkMenu::ConnectToNetworkAt(int index, - const std::string& passphrase, - const std::string& ssid, - int auto_connect) const { +bool NetworkMenuModel::ConnectToNetworkAt(int index, + const std::string& passphrase, + const std::string& ssid, + int auto_connect) const { int flags = menu_items_[index].flags; NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); - const std::string& service_path = menu_items_[index].wireless_path; + const std::string& service_path = menu_items_[index].service_path; if (flags & FLAG_WIFI) { WifiNetwork* wifi = cros->FindWifiNetworkByPath(service_path); if (wifi) { @@ -115,6 +94,8 @@ bool NetworkMenu::ConnectToNetworkAt(int index, } else { // If we are attempting to connect to a network that no longer exists, // display a notification. + LOG(WARNING) << "Wi-fi network does not exist to connect to: " + << service_path; // TODO(stevenjb): Show notification. } } else if (flags & FLAG_CELLULAR) { @@ -137,43 +118,70 @@ bool NetworkMenu::ConnectToNetworkAt(int index, } else { // If we are attempting to connect to a network that no longer exists, // display a notification. + LOG(WARNING) << "Cellular network does not exist to connect to: " + << service_path; + // TODO(stevenjb): Show notification. + } + } else if (flags & FLAG_ADD_WIFI) { + ShowOther(TYPE_WIFI); + } else if (flags & FLAG_ADD_VPN) { + ShowOther(TYPE_VPN); + } else if (flags & FLAG_VPN) { + VirtualNetwork* vpn = cros->FindVirtualNetworkByPath(service_path); + if (vpn) { + // Connect or reconnect. + if (vpn->connecting_or_connected()) { + // Show the config settings for the connected network. + if (cros->connected_network()) + ShowTabbedNetworkSettings(cros->connected_network()); + return true; + } + // Show the connection UI if info for a field is missing. + if (vpn->NeedMoreInfoToConnect()) { + ShowNetworkConfigView(new NetworkConfigView(vpn)); + return true; + } + cros->ConnectToVirtualNetwork(vpn); + // Connection failures are responsible for updating the UI, including + // reopening dialogs. + return true; + } else { + // If we are attempting to connect to a network that no longer exists, + // display a notification. + LOG(WARNING) << "VPN does not exist to connect to: " << service_path; // TODO(stevenjb): Show notification. } - } else if (flags & FLAG_OTHER_WIFI_NETWORK) { - ShowOtherWifi(); - } else if (flags & FLAG_OTHER_CELLULAR_NETWORK) { - ShowOtherCellular(); } return true; } //////////////////////////////////////////////////////////////////////////////// -// NetworkMenu, ui::MenuModel implementation: +// NetworkMenuModel, ui::MenuModel implementation: -int NetworkMenu::GetItemCount() const { +int NetworkMenuModel::GetItemCount() const { return static_cast<int>(menu_items_.size()); } -ui::MenuModel::ItemType NetworkMenu::GetTypeAt(int index) const { +ui::MenuModel::ItemType NetworkMenuModel::GetTypeAt(int index) const { return menu_items_[index].type; } -string16 NetworkMenu::GetLabelAt(int index) const { +string16 NetworkMenuModel::GetLabelAt(int index) const { return menu_items_[index].label; } -const gfx::Font* NetworkMenu::GetLabelFontAt(int index) const { +const gfx::Font* NetworkMenuModel::GetLabelFontAt(int index) const { return (menu_items_[index].flags & FLAG_ASSOCIATED) ? &ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BoldFont) : NULL; } -bool NetworkMenu::IsItemCheckedAt(int index) const { +bool NetworkMenuModel::IsItemCheckedAt(int index) const { // All ui::MenuModel::TYPE_CHECK menu items are checked. return true; } -bool NetworkMenu::GetIconAt(int index, SkBitmap* icon) { +bool NetworkMenuModel::GetIconAt(int index, SkBitmap* icon) { if (!menu_items_[index].icon.empty()) { *icon = menu_items_[index].icon; return true; @@ -181,19 +189,23 @@ bool NetworkMenu::GetIconAt(int index, SkBitmap* icon) { return false; } -bool NetworkMenu::IsEnabledAt(int index) const { +bool NetworkMenuModel::IsEnabledAt(int index) const { return !(menu_items_[index].flags & FLAG_DISABLED); } -void NetworkMenu::ActivatedAt(int index) { +ui::MenuModel* NetworkMenuModel::GetSubmenuModelAt(int index) const { + return menu_items_[index].sub_menu_model; +} + +void NetworkMenuModel::ActivatedAt(int index) { // When we are refreshing the menu, ignore menu item activation. - if (refreshing_menu_) + if (owner_->refreshing_menu_) return; NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); int flags = menu_items_[index].flags; if (flags & FLAG_OPTIONS) { - OpenButtonOptions(); + owner_->OpenButtonOptions(); } else if (flags & FLAG_TOGGLE_ETHERNET) { cros->EnableEthernetNetworkDevice(!cros->ethernet_enabled()); } else if (flags & FLAG_TOGGLE_WIFI) { @@ -208,7 +220,7 @@ void NetworkMenu::ActivatedAt(int index) { cellular->sim_lock_state() == SIM_UNKNOWN) { cros->EnableCellularNetworkDevice(!cros->cellular_enabled()); } else { - SimUnlockDialogDelegate::ShowDialog(GetNativeWindow()); + SimUnlockDialogDelegate::ShowDialog(owner_->GetNativeWindow()); } } } else if (flags & FLAG_TOGGLE_OFFLINE) { @@ -217,251 +229,88 @@ void NetworkMenu::ActivatedAt(int index) { if (cros->ethernet_connected()) { ShowTabbedNetworkSettings(cros->ethernet_network()); } - } else if (flags & FLAG_WIFI) { - ConnectToNetworkAt(index, std::string(), std::string(), -1); - } else if (flags & FLAG_OTHER_WIFI_NETWORK) { - ConnectToNetworkAt(index, std::string(), std::string(), -1); - } else if (flags & FLAG_CELLULAR) { - ConnectToNetworkAt(index, std::string(), std::string(), -1); - } else if (flags & FLAG_OTHER_CELLULAR_NETWORK) { + } else if (flags & (FLAG_WIFI | FLAG_ADD_WIFI | + FLAG_CELLULAR | FLAG_ADD_CELLULAR | + FLAG_VPN | FLAG_ADD_VPN)) { ConnectToNetworkAt(index, std::string(), std::string(), -1); + } else if (flags & FLAG_DISCONNECT_VPN) { + const VirtualNetwork* active_vpn = cros->virtual_network(); + if (active_vpn) + cros->DisconnectFromNetwork(active_vpn); } } -void NetworkMenu::SetFirstLevelMenuWidth(int width) { - min_width_ = width; - // This actually has no effect since menu is rebuilt before showing. - network_menu_->SetMinimumWidth(width); -} - -void NetworkMenu::CancelMenu() { - network_menu_->CancelMenu(); -} +//////////////////////////////////////////////////////////////////////////////// +// NetworkMenuModel, private methods: -void NetworkMenu::UpdateMenu() { - refreshing_menu_ = true; - InitMenuItems(); - network_menu_->Rebuild(); - refreshing_menu_ = false; +void NetworkMenuModel::ShowTabbedNetworkSettings(const Network* network) const { + DCHECK(network); + Browser* browser = BrowserList::GetLastActive(); + if (!browser) + return; + std::string page = StringPrintf("%s?servicePath=%s&networkType=%d", + chrome::kInternetOptionsSubPage, + EscapeUrlEncodedData(network->service_path()).c_str(), + network->type()); + browser->ShowOptionsTab(page); } -// static -const SkBitmap* NetworkMenu::IconForNetworkStrength(const WifiNetwork* wifi, - bool black) { - DCHECK(wifi); - if (wifi->strength() == 0) { - return ResourceBundle::GetSharedInstance().GetBitmapNamed( - black ? IDR_STATUSBAR_NETWORK_BARS0_BLACK : - IDR_STATUSBAR_NETWORK_BARS0); - } - int index = static_cast<int>(wifi->strength() / 100.0 * - nextafter(static_cast<float>(kNumBarsImages), 0)); - index = std::max(std::min(index, kNumBarsImages - 1), 0); - const int* images = black ? kBarsImagesBlack : kBarsImages; - return ResourceBundle::GetSharedInstance().GetBitmapNamed(images[index]); +// TODO(stevenjb): deprecate this once we've committed to tabbed settings +// and the embedded menu UI (and fully deprecated NetworkConfigView). +// Meanwhile, if MenuUI::IsEnabled() is true, always show the settings UI, +// otherwise show NetworkConfigView only to get passwords when not connected. +void NetworkMenuModel::ShowNetworkConfigView(NetworkConfigView* view) const { + view->set_browser_mode(owner_->IsBrowserMode()); + views::Window* window = browser::CreateViewsWindow( + owner_->GetNativeWindow(), gfx::Rect(), view); + window->SetIsAlwaysOnTop(true); + window->Show(); } -// static -const SkBitmap* NetworkMenu::IconForNetworkStrength( - const CellularNetwork* cellular, bool black) { +void NetworkMenuModel::ActivateCellular(const CellularNetwork* cellular) const { DCHECK(cellular); - // If no data, then we show 0 bars. - if (cellular->strength() == 0 || - cellular->data_left() == CellularNetwork::DATA_NONE) { - return ResourceBundle::GetSharedInstance().GetBitmapNamed( - black ? IDR_STATUSBAR_NETWORK_BARS0_BLACK : - IDR_STATUSBAR_NETWORK_BARS0); - } - int index = static_cast<int>(cellular->strength() / 100.0 * - nextafter(static_cast<float>(kNumBarsImages), 0)); - index = std::max(std::min(index, kNumBarsImages - 1), 0); - const int* images = black ? kBarsImagesBlack : kBarsImages; - return ResourceBundle::GetSharedInstance().GetBitmapNamed(images[index]); -} - -// static -const SkBitmap* NetworkMenu::IconForNetworkConnecting(double animation_value, - bool black) { - // Draw animation of bars icon fading in and out. - // We are fading between 0 bars and a third of the opacity of 4 bars. - // Use the current value of the animation to calculate the alpha value - // of how transparent the icon is. - - int index = static_cast<int>(animation_value * - nextafter(static_cast<float>(kNumAnimatingImages), 0)); - index = std::max(std::min(index, kNumAnimatingImages - 1), 0); - - SkBitmap* images = black ? kAnimatingImagesBlack : kAnimatingImages; - // Lazily cache images. - if (images[index].empty()) { - // Divide index (0-9) by 9 (assume kNumAnimatingImages==10) to get (0.0-1.0) - // Then we take a third of that for the alpha value. - double alpha = (static_cast<double>(index) / (kNumAnimatingImages - 1)) / 3; - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - images[index] = SkBitmapOperations::CreateBlendedBitmap( - *rb.GetBitmapNamed(black ? IDR_STATUSBAR_NETWORK_BARS0_BLACK : - IDR_STATUSBAR_NETWORK_BARS0), - *rb.GetBitmapNamed(black ? IDR_STATUSBAR_NETWORK_BARS4_BLACK : - IDR_STATUSBAR_NETWORK_BARS4), - alpha); - } - return &images[index]; -} - -// static -const SkBitmap* NetworkMenu::BadgeForNetworkTechnology( - const CellularNetwork* cellular) { - if (!cellular) - return NULL; - - int id = -1; - switch (cellular->network_technology()) { - case NETWORK_TECHNOLOGY_EVDO: - switch (cellular->data_left()) { - case CellularNetwork::DATA_NONE: - id = IDR_STATUSBAR_NETWORK_3G_ERROR; - break; - case CellularNetwork::DATA_VERY_LOW: - case CellularNetwork::DATA_LOW: - case CellularNetwork::DATA_NORMAL: - id = IDR_STATUSBAR_NETWORK_3G; - break; - case CellularNetwork::DATA_UNKNOWN: - id = IDR_STATUSBAR_NETWORK_3G_UNKNOWN; - break; - } - break; - case NETWORK_TECHNOLOGY_1XRTT: - switch (cellular->data_left()) { - case CellularNetwork::DATA_NONE: - id = IDR_STATUSBAR_NETWORK_1X_ERROR; - break; - case CellularNetwork::DATA_VERY_LOW: - case CellularNetwork::DATA_LOW: - case CellularNetwork::DATA_NORMAL: - id = IDR_STATUSBAR_NETWORK_1X; - break; - case CellularNetwork::DATA_UNKNOWN: - id = IDR_STATUSBAR_NETWORK_1X_UNKNOWN; - break; - } - break; - // Note: we may not be able to obtain data usage info - // from GSM carriers, so there may not be a reason - // to create _ERROR or _UNKNOWN versions of the following - // icons. - case NETWORK_TECHNOLOGY_GPRS: - id = IDR_STATUSBAR_NETWORK_GPRS; - break; - case NETWORK_TECHNOLOGY_EDGE: - id = IDR_STATUSBAR_NETWORK_EDGE; - break; - case NETWORK_TECHNOLOGY_UMTS: - id = IDR_STATUSBAR_NETWORK_3G; - break; - case NETWORK_TECHNOLOGY_HSPA: - id = IDR_STATUSBAR_NETWORK_HSPA; - break; - case NETWORK_TECHNOLOGY_HSPA_PLUS: - id = IDR_STATUSBAR_NETWORK_HSPA_PLUS; - break; - case NETWORK_TECHNOLOGY_LTE: - id = IDR_STATUSBAR_NETWORK_LTE; - break; - case NETWORK_TECHNOLOGY_LTE_ADVANCED: - id = IDR_STATUSBAR_NETWORK_LTE_ADVANCED; - break; - case NETWORK_TECHNOLOGY_UNKNOWN: - break; - } - if (id == -1) - return NULL; - else - return ResourceBundle::GetSharedInstance().GetBitmapNamed(id); -} - -// static -const SkBitmap* NetworkMenu::BadgeForRoamingStatus( - const CellularNetwork* cellular) { - // TODO(nkostylev): Return "R" badge, http://crosbug.com/12010. - if (cellular->roaming_state() == ROAMING_STATE_ROAMING) - return NULL; - else - return NULL; + Browser* browser = BrowserList::GetLastActive(); + if (!browser) + return; + browser->OpenMobilePlanTabAndActivate(); } -// static -SkBitmap NetworkMenu::IconForDisplay(const SkBitmap* icon, - const SkBitmap* badge) { - return IconForDisplay(icon, badge, NULL); +void NetworkMenuModel::ShowOther(ConnectionType type) const { + ShowNetworkConfigView(new NetworkConfigView(type)); } -// static -SkBitmap NetworkMenu::IconForDisplay(const SkBitmap* icon, - const SkBitmap* bottom_right_badge, - const SkBitmap* top_left_badge) { - DCHECK(icon); - if (bottom_right_badge == NULL && top_left_badge == NULL) - return *icon; - - static const int kTopLeftBadgeX = 0; - static const int kTopLeftBadgeY = 0; - static const int kBottomRightBadgeX = 14; - static const int kBottomRightBadgeY = 14; - - gfx::CanvasSkia canvas(icon->width(), icon->height(), false); - canvas.DrawBitmapInt(*icon, 0, 0); - if (bottom_right_badge != NULL) - canvas.DrawBitmapInt(*bottom_right_badge, - kBottomRightBadgeX, - kBottomRightBadgeY); - if (top_left_badge != NULL) - canvas.DrawBitmapInt(*top_left_badge, kTopLeftBadgeX, kTopLeftBadgeY); - return canvas.ExtractBitmap(); +void NetworkMenuModel::ShowOtherCellular() const { + ChooseMobileNetworkDialog::ShowDialog(owner_->GetNativeWindow()); } //////////////////////////////////////////////////////////////////////////////// -// NetworkMenu, views::ViewMenuDelegate implementation: - -void NetworkMenu::RunMenu(views::View* source, const gfx::Point& pt) { - refreshing_menu_ = true; - NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); - cros->RequestNetworkScan(); - - // Build initial menu items. They will be updated when UpdateMenu is - // called from NetworkChanged. - InitMenuItems(); - network_menu_->Rebuild(); +// MainMenuModel - // Restore menu width, if it was set up. - // NOTE: width isn't checked for correctness here since all width-related - // logic implemented inside |network_menu_|. - if (min_width_ != -1) - network_menu_->SetMinimumWidth(min_width_); - refreshing_menu_ = false; - network_menu_->RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT); +MainMenuModel::MainMenuModel(NetworkMenu* owner) + : NetworkMenuModel(owner) { + vpn_menu_model_.reset(new VPNMenuModel(owner)); } -void NetworkMenu::InitMenuItems() { +void MainMenuModel::InitMenuItems(bool is_browser_mode, + bool should_open_button_options) { // This gets called on initialization, so any changes should be reflected // in CrosMock::SetNetworkLibraryStatusAreaExpectations(). menu_items_.clear(); - // Populate our MenuItems with the current list of wifi networks. - NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - - string16 label; + NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); if (cros->IsLocked()) { - label = l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_LOCKED); menu_items_.push_back( MenuItem(ui::MenuModel::TYPE_COMMAND, - label, SkBitmap(), - std::string(), FLAG_DISABLED)); + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_LOCKED), + SkBitmap(), std::string(), FLAG_DISABLED)); return; } + // Populate our MenuItems with the current list of networks. + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + string16 label; + // Ethernet bool ethernet_available = cros->ethernet_available(); bool ethernet_enabled = cros->ethernet_enabled(); @@ -485,7 +334,8 @@ void NetworkMenu::InitMenuItems() { flag |= FLAG_ASSOCIATED; menu_items_.push_back( MenuItem(ui::MenuModel::TYPE_COMMAND, label, - IconForDisplay(icon, badge), std::string(), flag)); + NetworkMenu::IconForDisplay(icon, badge), std::string(), + flag)); } // Wifi Networks @@ -515,20 +365,21 @@ void NetworkMenu::InitMenuItems() { } } - const SkBitmap* icon = IconForNetworkStrength(wifi_networks[i], true); + const SkBitmap* icon = NetworkMenu::IconForNetworkStrength( + wifi_networks[i], true); const SkBitmap* badge = wifi_networks[i]->encrypted() ? rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE) : NULL; int flag = FLAG_WIFI; // If a network is not connectable from login/oobe, we disable it. // We do not allow configuring a network (e.g. 802.1x) from login/oobe. - if (!IsBrowserMode() && !wifi_networks[i]->connectable()) + if (!owner_->IsBrowserMode() && !wifi_networks[i]->connectable()) flag |= FLAG_DISABLED; if (active_wifi && wifi_networks[i]->service_path() == active_wifi->service_path()) flag |= FLAG_ASSOCIATED; menu_items_.push_back( MenuItem(ui::MenuModel::TYPE_COMMAND, label, - IconForDisplay(icon, badge), + NetworkMenu::IconForDisplay(icon, badge), wifi_networks[i]->service_path(), flag)); } if (!separator_added && !menu_items_.empty()) @@ -537,7 +388,7 @@ void NetworkMenu::InitMenuItems() { ui::MenuModel::TYPE_COMMAND, l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_OTHER_WIFI_NETWORKS), *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0_BLACK), - std::string(), FLAG_OTHER_WIFI_NETWORK)); + std::string(), FLAG_ADD_WIFI)); } // Cellular Networks @@ -558,7 +409,7 @@ void NetworkMenu::InitMenuItems() { is_gsm = true; // If we are on the OOBE/login screen, do not show activating 3G option. - if (!IsBrowserMode() && activation_state != ACTIVATION_STATE_ACTIVATED) + if (!is_browser_mode && activation_state != ACTIVATION_STATE_ACTIVATED) continue; if (activation_state == ACTIVATION_STATE_NOT_ACTIVATED || @@ -588,9 +439,12 @@ void NetworkMenu::InitMenuItems() { } } - const SkBitmap* icon = IconForNetworkStrength(cell_networks[i], true); - const SkBitmap* badge = BadgeForNetworkTechnology(cell_networks[i]); - const SkBitmap* roaming_badge = BadgeForRoamingStatus(cell_networks[i]); + const SkBitmap* icon = NetworkMenu::IconForNetworkStrength( + cell_networks[i], true); + const SkBitmap* badge = NetworkMenu::BadgeForNetworkTechnology( + cell_networks[i]); + const SkBitmap* roaming_badge = NetworkMenu::BadgeForRoamingStatus( + cell_networks[i]); int flag = FLAG_CELLULAR; bool isActive = active_cellular && cell_networks[i]->service_path() == active_cellular->service_path() && @@ -599,7 +453,8 @@ void NetworkMenu::InitMenuItems() { flag |= FLAG_ASSOCIATED; menu_items_.push_back( MenuItem(ui::MenuModel::TYPE_COMMAND, label, - IconForDisplay(icon, badge, roaming_badge), + NetworkMenu::IconForDisplay(icon, badge, roaming_badge, + NULL), cell_networks[i]->service_path(), flag)); if (isActive) { label.clear(); @@ -630,7 +485,7 @@ void NetworkMenu::InitMenuItems() { l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_OTHER_CELLULAR_NETWORKS), *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0_BLACK), - std::string(), FLAG_OTHER_CELLULAR_NETWORK)); + std::string(), FLAG_ADD_CELLULAR)); } } @@ -642,6 +497,19 @@ void NetworkMenu::InitMenuItems() { SkBitmap(), std::string(), FLAG_DISABLED)); } + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableVPN)) { + // If there's a connected network, add submenu for Private Networks. + const Network* connected_network = cros->connected_network(); + if (connected_network) { + menu_items_.push_back(MenuItem()); // Separator + menu_items_.push_back(MenuItem( + ui::MenuModel::TYPE_SUBMENU, + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_PRIVATE_NETWORKS), + VPNMenuModel::IconForDisplay(connected_network), + vpn_menu_model_.get(), FLAG_PRIVATE_NETWORKS)); + } + } + // Enable / disable wireless. if (wifi_available || cellular_available) { menu_items_.push_back(MenuItem()); // Separator @@ -692,7 +560,7 @@ void NetworkMenu::InitMenuItems() { // SkBitmap(), std::string(), FLAG_TOGGLE_OFFLINE)); bool connected = cros->Connected(); // always call for test expectations. - bool oobe = !ShouldOpenButtonOptions(); // we don't show options for OOBE. + bool oobe = !should_open_button_options; // we don't show options for OOBE. // Network settings. (And IP Address) if (!oobe) { menu_items_.push_back(MenuItem()); // Separator @@ -706,52 +574,420 @@ void NetworkMenu::InitMenuItems() { } } - label = l10n_util::GetStringUTF16(IsBrowserMode() ? + label = l10n_util::GetStringUTF16(is_browser_mode ? IDS_STATUSBAR_NETWORK_OPEN_OPTIONS_DIALOG : IDS_STATUSBAR_NETWORK_OPEN_PROXY_SETTINGS_DIALOG); menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label, SkBitmap(), std::string(), FLAG_OPTIONS)); } + + // Recursively call each submenu to populate its own menu items. + for (size_t i = 0; i < menu_items_.size(); ++i) { + if (menu_items_[i].type == ui::MenuModel::TYPE_SUBMENU && + menu_items_[i].sub_menu_model) { + menu_items_[i].sub_menu_model->InitMenuItems(is_browser_mode, + should_open_button_options); + } + } } -void NetworkMenu::ShowTabbedNetworkSettings(const Network* network) const { - DCHECK(network); - Browser* browser = BrowserList::GetLastActive(); - if (!browser) +//////////////////////////////////////////////////////////////////////////////// +// VPNMenuModel + +VPNMenuModel::VPNMenuModel(NetworkMenu* owner) + : NetworkMenuModel(owner) { +} + +void VPNMenuModel::InitMenuItems(bool is_browser_mode, + bool should_open_button_options) { + // This gets called on initialization, so any changes should be reflected + // in CrosMock::SetNetworkLibraryStatusAreaExpectations(). + + menu_items_.clear(); + + // VPN only applies if there's a connected underlying network. + NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); + const Network* connected_network = cros->connected_network(); + if (!connected_network) return; - std::string page = StringPrintf("%s?servicePath=%s&networkType=%d", - chrome::kInternetOptionsSubPage, - EscapeUrlEncodedData(network->service_path()).c_str(), - network->type()); - browser->ShowOptionsTab(page); + + // Populate our MenuItems with the current list of virtual networks. + const VirtualNetworkVector& virtual_networks = cros->virtual_networks(); + const VirtualNetwork* active_vpn = cros->virtual_network(); + SkBitmap icon = VPNMenuModel::IconForDisplay(connected_network); + bool separator_added = false; + string16 label; + + for (size_t i = 0; i < virtual_networks.size(); ++i) { + const VirtualNetwork* vpn = virtual_networks[i]; + if (vpn->connecting()) { + label = l10n_util::GetStringFUTF16( + IDS_STATUSBAR_NETWORK_DEVICE_STATUS, + ASCIIToUTF16(vpn->name()), + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING)); + } else { + label = ASCIIToUTF16(vpn->name()); + } + + // First add a separator if necessary. + if (!separator_added) { + separator_added = true; + if (!menu_items_.empty()) { // Don't add if first menu item. + menu_items_.push_back(MenuItem()); // Separator + } + } + + int flag = FLAG_VPN; + if (!vpn->connectable()) + flag |= FLAG_DISABLED; + if (active_vpn && vpn->service_path() == active_vpn->service_path()) + flag |= FLAG_ASSOCIATED; + menu_items_.push_back( + MenuItem(ui::MenuModel::TYPE_COMMAND, label, icon, vpn->service_path(), + flag)); + } + + // Add option to add/disconnect from vpn. + if (!menu_items_.empty()) { // Add separator if menu is not empty. + menu_items_.push_back(MenuItem()); + } + menu_items_.push_back(MenuItem( + ui::MenuModel::TYPE_COMMAND, + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_ADD_VPN), + SkBitmap(), std::string(), FLAG_ADD_VPN)); + if (active_vpn) { + menu_items_.push_back(MenuItem( + ui::MenuModel::TYPE_COMMAND, + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DISCONNECT_VPN), + SkBitmap(), std::string(), FLAG_DISCONNECT_VPN)); + } } -// TODO(stevenjb): deprecate this once we've committed to tabbed settings -// and the embedded menu UI (and fully deprecated NetworkConfigView). -// Meanwhile, if MenuUI::IsEnabled() is true, always show the settings UI, -// otherwise show NetworkConfigView only to get passwords when not connected. -void NetworkMenu::ShowNetworkConfigView(NetworkConfigView* view) const { - view->set_browser_mode(IsBrowserMode()); - views::Window* window = browser::CreateViewsWindow( - GetNativeWindow(), gfx::Rect(), view); - window->SetIsAlwaysOnTop(true); - window->Show(); +// static +SkBitmap VPNMenuModel::IconForDisplay(const Network* network) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + const SkBitmap* icon = NULL; + const SkBitmap* bottom_right_badge = NULL; + const SkBitmap* top_left_badge = NULL; + // We know for sure |network| is the active network, so no more checking + // is needed by BadgeForPrivateNetworkStatus, hence pass in NULL. + const SkBitmap* bottom_left_badge = + NetworkMenu::BadgeForPrivateNetworkStatus(NULL); + + switch (network->type()) { + case TYPE_ETHERNET : + icon = rb.GetBitmapNamed(IDR_STATUSBAR_WIRED_BLACK); + break; + case TYPE_WIFI : + icon = NetworkMenu::IconForNetworkStrength( + static_cast<const WifiNetwork*>(network), true); + break; + case TYPE_CELLULAR : { + const CellularNetwork* cellular = + static_cast<const CellularNetwork*>(network); + icon = NetworkMenu::IconForNetworkStrength(cellular, true); + bottom_right_badge = NetworkMenu::BadgeForNetworkTechnology(cellular); + top_left_badge = NetworkMenu::BadgeForRoamingStatus(cellular); + break; + } + default: + LOG(WARNING) << "VPN not handled for connection type " << network->type(); + return SkBitmap(); + } + + return NetworkMenu::IconForDisplay(icon, bottom_right_badge, top_left_badge, + bottom_left_badge); } -void NetworkMenu::ActivateCellular(const CellularNetwork* cellular) const { +//////////////////////////////////////////////////////////////////////////////// +// NetworkMenu + +// static +const int NetworkMenu::kNumBarsImages = 4; + +// NOTE: Use an array rather than just calculating a resource number to avoid +// creating implicit ordering dependencies on the resource values. +// static +const int NetworkMenu::kBarsImages[kNumBarsImages] = { + IDR_STATUSBAR_NETWORK_BARS1, + IDR_STATUSBAR_NETWORK_BARS2, + IDR_STATUSBAR_NETWORK_BARS3, + IDR_STATUSBAR_NETWORK_BARS4, +}; +// static +const int NetworkMenu::kBarsImagesBlack[kNumBarsImages] = { + IDR_STATUSBAR_NETWORK_BARS1_BLACK, + IDR_STATUSBAR_NETWORK_BARS2_BLACK, + IDR_STATUSBAR_NETWORK_BARS3_BLACK, + IDR_STATUSBAR_NETWORK_BARS4_BLACK, +}; +/* +// static +const int NetworkMenu::kBarsImagesLowData[kNumBarsImages] = { + IDR_STATUSBAR_NETWORK_BARS1_ORANGE, + IDR_STATUSBAR_NETWORK_BARS2_ORANGE, + IDR_STATUSBAR_NETWORK_BARS3_ORANGE, + IDR_STATUSBAR_NETWORK_BARS4_ORANGE, +}; +// static +const int NetworkMenu::kBarsImagesVLowData[kNumBarsImages] = { + IDR_STATUSBAR_NETWORK_BARS1_RED, + IDR_STATUSBAR_NETWORK_BARS2_RED, + IDR_STATUSBAR_NETWORK_BARS3_RED, + IDR_STATUSBAR_NETWORK_BARS4_RED, +}; +*/ + +// static +const int NetworkMenu::kNumAnimatingImages = 10; + +// static +SkBitmap NetworkMenu::kAnimatingImages[kNumAnimatingImages]; + +// static +SkBitmap NetworkMenu::kAnimatingImagesBlack[kNumAnimatingImages]; + +NetworkMenu::NetworkMenu() + : min_width_(-1) { + main_menu_model_.reset(new MainMenuModel(this)); + network_menu_.reset(new views::Menu2(main_menu_model_.get())); +} + +NetworkMenu::~NetworkMenu() { +} + +void NetworkMenu::SetFirstLevelMenuWidth(int width) { + min_width_ = width; + // This actually has no effect since menu is rebuilt before showing. + network_menu_->SetMinimumWidth(width); +} + +void NetworkMenu::CancelMenu() { + network_menu_->CancelMenu(); +} + +void NetworkMenu::UpdateMenu() { + refreshing_menu_ = true; + main_menu_model_->InitMenuItems(IsBrowserMode(), ShouldOpenButtonOptions()); + network_menu_->Rebuild(); + refreshing_menu_ = false; +} + +// static +const SkBitmap* NetworkMenu::IconForNetworkStrength(const WifiNetwork* wifi, + bool black) { + DCHECK(wifi); + if (wifi->strength() == 0) { + return ResourceBundle::GetSharedInstance().GetBitmapNamed( + black ? IDR_STATUSBAR_NETWORK_BARS0_BLACK : + IDR_STATUSBAR_NETWORK_BARS0); + } + int index = static_cast<int>(wifi->strength() / 100.0 * + nextafter(static_cast<float>(kNumBarsImages), 0)); + index = std::max(std::min(index, kNumBarsImages - 1), 0); + const int* images = black ? kBarsImagesBlack : kBarsImages; + return ResourceBundle::GetSharedInstance().GetBitmapNamed(images[index]); +} + +// static +const SkBitmap* NetworkMenu::IconForNetworkStrength( + const CellularNetwork* cellular, bool black) { DCHECK(cellular); - Browser* browser = BrowserList::GetLastActive(); - if (!browser) - return; - browser->OpenMobilePlanTabAndActivate(); + // If no data, then we show 0 bars. + if (cellular->strength() == 0 || + cellular->data_left() == CellularNetwork::DATA_NONE) { + return ResourceBundle::GetSharedInstance().GetBitmapNamed( + black ? IDR_STATUSBAR_NETWORK_BARS0_BLACK : + IDR_STATUSBAR_NETWORK_BARS0); + } + int index = static_cast<int>(cellular->strength() / 100.0 * + nextafter(static_cast<float>(kNumBarsImages), 0)); + index = std::max(std::min(index, kNumBarsImages - 1), 0); + const int* images = black ? kBarsImagesBlack : kBarsImages; + return ResourceBundle::GetSharedInstance().GetBitmapNamed(images[index]); } -void NetworkMenu::ShowOtherWifi() const { - ShowNetworkConfigView(new NetworkConfigView()); +// static +const SkBitmap* NetworkMenu::IconForNetworkConnecting(double animation_value, + bool black) { + // Draw animation of bars icon fading in and out. + // We are fading between 0 bars and a third of the opacity of 4 bars. + // Use the current value of the animation to calculate the alpha value + // of how transparent the icon is. + int index = static_cast<int>(animation_value * + nextafter(static_cast<float>(kNumAnimatingImages), 0)); + index = std::max(std::min(index, kNumAnimatingImages - 1), 0); + + SkBitmap* images = black ? kAnimatingImagesBlack : kAnimatingImages; + // Lazily cache images. + if (images[index].empty()) { + // Divide index (0-9) by 9 (assume kNumAnimatingImages==10) to get (0.0-1.0) + // Then we take a third of that for the alpha value. + double alpha = (static_cast<double>(index) / (kNumAnimatingImages - 1)) / 3; + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + images[index] = SkBitmapOperations::CreateBlendedBitmap( + *rb.GetBitmapNamed(black ? IDR_STATUSBAR_NETWORK_BARS0_BLACK : + IDR_STATUSBAR_NETWORK_BARS0), + *rb.GetBitmapNamed(black ? IDR_STATUSBAR_NETWORK_BARS4_BLACK : + IDR_STATUSBAR_NETWORK_BARS4), + alpha); + } + return &images[index]; +} + +// static +const SkBitmap* NetworkMenu::BadgeForNetworkTechnology( + const CellularNetwork* cellular) { + if (!cellular) + return NULL; + + int id = -1; + switch (cellular->network_technology()) { + case NETWORK_TECHNOLOGY_EVDO: + switch (cellular->data_left()) { + case CellularNetwork::DATA_NONE: + id = IDR_STATUSBAR_NETWORK_3G_ERROR; + break; + case CellularNetwork::DATA_VERY_LOW: + case CellularNetwork::DATA_LOW: + case CellularNetwork::DATA_NORMAL: + id = IDR_STATUSBAR_NETWORK_3G; + break; + case CellularNetwork::DATA_UNKNOWN: + id = IDR_STATUSBAR_NETWORK_3G_UNKNOWN; + break; + } + break; + case NETWORK_TECHNOLOGY_1XRTT: + switch (cellular->data_left()) { + case CellularNetwork::DATA_NONE: + id = IDR_STATUSBAR_NETWORK_1X_ERROR; + break; + case CellularNetwork::DATA_VERY_LOW: + case CellularNetwork::DATA_LOW: + case CellularNetwork::DATA_NORMAL: + id = IDR_STATUSBAR_NETWORK_1X; + break; + case CellularNetwork::DATA_UNKNOWN: + id = IDR_STATUSBAR_NETWORK_1X_UNKNOWN; + break; + } + break; + // Note: we may not be able to obtain data usage info + // from GSM carriers, so there may not be a reason + // to create _ERROR or _UNKNOWN versions of the following + // icons. + case NETWORK_TECHNOLOGY_GPRS: + id = IDR_STATUSBAR_NETWORK_GPRS; + break; + case NETWORK_TECHNOLOGY_EDGE: + id = IDR_STATUSBAR_NETWORK_EDGE; + break; + case NETWORK_TECHNOLOGY_UMTS: + id = IDR_STATUSBAR_NETWORK_3G; + break; + case NETWORK_TECHNOLOGY_HSPA: + id = IDR_STATUSBAR_NETWORK_HSPA; + break; + case NETWORK_TECHNOLOGY_HSPA_PLUS: + id = IDR_STATUSBAR_NETWORK_HSPA_PLUS; + break; + case NETWORK_TECHNOLOGY_LTE: + id = IDR_STATUSBAR_NETWORK_LTE; + break; + case NETWORK_TECHNOLOGY_LTE_ADVANCED: + id = IDR_STATUSBAR_NETWORK_LTE_ADVANCED; + break; + case NETWORK_TECHNOLOGY_UNKNOWN: + break; + } + if (id == -1) + return NULL; + else + return ResourceBundle::GetSharedInstance().GetBitmapNamed(id); +} + +// static +const SkBitmap* NetworkMenu::BadgeForRoamingStatus( + const CellularNetwork* cellular) { + // TODO(nkostylev): Return "R" badge, http://crosbug.com/12010. + if (cellular->roaming_state() == ROAMING_STATE_ROAMING) + return NULL; + else + return NULL; +} + +const SkBitmap* NetworkMenu::BadgeForPrivateNetworkStatus( + const Network* network) { + // If network is not null, check if it's the active network with vpn on it. + if (network) { + NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); + if (!(cros->virtual_network() && network == cros->connected_network())) + return NULL; + } + // TODO(kuan): yellow lock icon not ready yet; for now, return the black one + // used by secure wifi network. + return ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_STATUSBAR_NETWORK_SECURE); +} + +// static +SkBitmap NetworkMenu::IconForDisplay(const SkBitmap* icon, + const SkBitmap* badge) { + return IconForDisplay(icon, badge, NULL, NULL); +} + +// static +SkBitmap NetworkMenu::IconForDisplay(const SkBitmap* icon, + const SkBitmap* bottom_right_badge, + const SkBitmap* top_left_badge, + const SkBitmap* bottom_left_badge) { + DCHECK(icon); + if (bottom_right_badge == NULL && top_left_badge == NULL && + bottom_left_badge == NULL) + return *icon; + + static const int kTopLeftBadgeX = 0; + static const int kTopLeftBadgeY = 0; + static const int kBottomRightBadgeX = 14; + static const int kBottomRightBadgeY = 14; + static const int kBottomLeftBadgeX = 0; + static const int kBottomLeftBadgeY = 14; + + gfx::CanvasSkia canvas(icon->width(), icon->height(), false); + canvas.DrawBitmapInt(*icon, 0, 0); + if (bottom_right_badge != NULL) + canvas.DrawBitmapInt(*bottom_right_badge, + kBottomRightBadgeX, + kBottomRightBadgeY); + if (top_left_badge != NULL) + canvas.DrawBitmapInt(*top_left_badge, kTopLeftBadgeX, kTopLeftBadgeY); + if (bottom_left_badge != NULL) + canvas.DrawBitmapInt(*bottom_left_badge, kBottomLeftBadgeX, + kBottomLeftBadgeY); + return canvas.ExtractBitmap(); } -void NetworkMenu::ShowOtherCellular() const { - ChooseMobileNetworkDialog::ShowDialog(GetNativeWindow()); +//////////////////////////////////////////////////////////////////////////////// +// NetworkMenu, views::ViewMenuDelegate implementation: + +void NetworkMenu::RunMenu(views::View* source, const gfx::Point& pt) { + refreshing_menu_ = true; + NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); + cros->RequestNetworkScan(); + + // Build initial menu items. They will be updated when UpdateMenu is + // called from NetworkChanged. + main_menu_model_->InitMenuItems(IsBrowserMode(), ShouldOpenButtonOptions()); + network_menu_->Rebuild(); + + // Restore menu width, if it was set up. + // NOTE: width isn't checked for correctness here since all width-related + // logic implemented inside |network_menu_|. + if (min_width_ != -1) + network_menu_->SetMinimumWidth(min_width_); + refreshing_menu_ = false; + network_menu_->RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT); } } // namespace chromeos diff --git a/chrome/browser/chromeos/status/network_menu.h b/chrome/browser/chromeos/status/network_menu.h index 13ad95b..05b1b88 100644 --- a/chrome/browser/chromeos/status/network_menu.h +++ b/chrome/browser/chromeos/status/network_menu.h @@ -11,7 +11,7 @@ #include "chrome/browser/chromeos/options/network_config_view.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/models/simple_menu_model.h" +#include "ui/base/models/menu_model.h" #include "ui/gfx/native_widget_types.h" #include "views/controls/menu/view_menu_delegate.h" @@ -25,31 +25,9 @@ class Menu2; namespace chromeos { -// Menu for network menu button in the status area/welcome screen. -// This class will populating the menu with the list of networks. -// It will also handle connecting to another wifi/cellular network. -// -// The network menu looks like this: -// -// <icon> Ethernet -// <icon> Wifi Network A -// <icon> Wifi Network B -// <icon> Wifi Network C -// <icon> Cellular Network A -// <icon> Cellular Network B -// <icon> Cellular Network C -// <icon> Other... -// -------------------------------- -// Disable Wifi -// Disable Celluar -// -------------------------------- -// <IP Address> -// Network settings... -// -// <icon> will show the strength of the wifi/cellular networks. -// The label will be BOLD if the network is currently connected. -class NetworkMenu : public views::ViewMenuDelegate, - public ui::MenuModel { +class NetworkMenu; + +class NetworkMenuModel : public ui::MenuModel { public: struct NetworkInfo { NetworkInfo() : @@ -72,8 +50,8 @@ class NetworkMenu : public views::ViewMenuDelegate, bool auto_connect; }; - NetworkMenu(); - virtual ~NetworkMenu(); + explicit NetworkMenuModel(NetworkMenu* owner) : owner_(owner) {} + virtual ~NetworkMenuModel() {} // Connect or reconnect to the network at |index|. // If remember >= 0, set the favorite state of the network. @@ -83,6 +61,10 @@ class NetworkMenu : public views::ViewMenuDelegate, const std::string& ssid, int remember) const; + // Called by NetworkMenu::RunMenu to initialize list of menu items. + virtual void InitMenuItems(bool is_browser_mode, + bool should_open_button_options) {} + // ui::MenuModel implementation. virtual bool HasIcons() const { return true; } virtual int GetItemCount() const; @@ -100,17 +82,122 @@ class NetworkMenu : public views::ViewMenuDelegate, return NULL; } virtual bool IsEnabledAt(int index) const; - virtual ui::MenuModel* GetSubmenuModelAt(int index) const { return NULL; } + virtual ui::MenuModel* GetSubmenuModelAt(int index) const; virtual void HighlightChangedTo(int index) {} virtual void ActivatedAt(int index); virtual void MenuWillShow() {} virtual void SetMenuModelDelegate(ui::MenuModelDelegate* delegate) {} + protected: + enum MenuItemFlags { + FLAG_DISABLED = 1 << 0, + FLAG_TOGGLE_ETHERNET = 1 << 1, + FLAG_TOGGLE_WIFI = 1 << 2, + FLAG_TOGGLE_CELLULAR = 1 << 3, + FLAG_TOGGLE_OFFLINE = 1 << 4, + FLAG_ASSOCIATED = 1 << 5, + FLAG_ETHERNET = 1 << 6, + FLAG_WIFI = 1 << 7, + FLAG_CELLULAR = 1 << 8, + FLAG_PRIVATE_NETWORKS = 1 << 9, + FLAG_OPTIONS = 1 << 10, + FLAG_ADD_WIFI = 1 << 11, + FLAG_ADD_CELLULAR = 1 << 12, + FLAG_VPN = 1 << 13, + FLAG_ADD_VPN = 1 << 14, + FLAG_DISCONNECT_VPN = 1 << 15, + }; + + struct MenuItem { + MenuItem() + : type(ui::MenuModel::TYPE_SEPARATOR), + sub_menu_model(NULL), + flags(0) {} + MenuItem(ui::MenuModel::ItemType type, string16 label, SkBitmap icon, + const std::string& service_path, int flags) + : type(type), + label(label), + icon(icon), + service_path(service_path), + sub_menu_model(NULL), + flags(flags) {} + MenuItem(ui::MenuModel::ItemType type, string16 label, SkBitmap icon, + NetworkMenuModel* sub_menu_model, int flags) + : type(type), + label(label), + icon(icon), + sub_menu_model(sub_menu_model), + flags(flags) {} + + ui::MenuModel::ItemType type; + string16 label; + SkBitmap icon; + std::string service_path; + NetworkMenuModel* sub_menu_model; // Weak. + int flags; + }; + typedef std::vector<MenuItem> MenuItemVector; + + // Our menu items. + MenuItemVector menu_items_; + + NetworkMenu* owner_; // Weak pointer to NetworkMenu that owns this MenuModel. + + private: + // Shows network details in Web UI options window. + void ShowTabbedNetworkSettings(const Network* network) const; + + // Show a NetworkConfigView modal dialog instance. + void ShowNetworkConfigView(NetworkConfigView* view) const; + + void ActivateCellular(const CellularNetwork* cellular) const; + void ShowOther(ConnectionType type) const; + void ShowOtherCellular() const; + + DISALLOW_COPY_AND_ASSIGN(NetworkMenuModel); +}; + +// Menu for network menu button in the status area/welcome screen. +// This class will populating the menu with the list of networks. +// It will also handle connecting to another wifi/cellular network. +// +// The network menu looks like this: +// +// <icon> Ethernet +// <icon> Wifi Network A +// <icon> Wifi Network B +// <icon> Wifi Network C +// <icon> Cellular Network A +// <icon> Cellular Network B +// <icon> Cellular Network C +// <icon> Other... +// <icon> Private networks -> +// <icon> Virtual Network A +// <icon> Virtual Network B +// ---------------------------------- +// Add private network... +// Disconnect private network +// -------------------------------- +// Disable Wifi +// Disable Celluar +// -------------------------------- +// <IP Address> +// Network settings... +// +// <icon> will show the strength of the wifi/cellular networks. +// The label will be BOLD if the network is currently connected. +class NetworkMenu : public views::ViewMenuDelegate { + public: + NetworkMenu(); + virtual ~NetworkMenu(); + void SetFirstLevelMenuWidth(int width); // Cancels the active menu. void CancelMenu(); + virtual bool IsBrowserMode() const = 0; + // The following methods returns pointer to a shared instance of the SkBitmap. // This shared bitmap is owned by the resource bundle and should not be freed. @@ -133,6 +220,7 @@ class NetworkMenu : public views::ViewMenuDelegate, // Expected to never return NULL. static const SkBitmap* IconForNetworkConnecting(double animation_value, bool black); + // Returns the Badge for a given network technology. // This returns different colored symbols depending on cellular data left. // Returns NULL if not badge is needed. @@ -142,21 +230,29 @@ class NetworkMenu : public views::ViewMenuDelegate, // This returns "R" badge if network is in roaming state, otherwise // returns NULL. Badge is supposed to be shown on top right of the icon. static const SkBitmap* BadgeForRoamingStatus(const CellularNetwork* cellular); + // Returns the badge for the given network if it's active with vpn. + // If |network| is not null, will check if it's the active network. + // If |network| is null or if |network| is the active one, the yellow lock + // badge will be returned, otherwise returns null. + // Badge is supposed to be shown on in bottom left corner of the icon. + static const SkBitmap* BadgeForPrivateNetworkStatus(const Network* network); + // This method will convert the |icon| bitmap to the correct size for display. // |icon| must be non-NULL. - // If the |badge| icon is not NULL, it will draw that on top of the icon. + // If |badge| icon is not NULL, it will be drawn on top of the icon in + // the bottom-right corner. static SkBitmap IconForDisplay(const SkBitmap* icon, const SkBitmap* badge); - // This method will convert the |icon| bitmap to the correct size for display. // |icon| must be non-NULL. - // If one of the |bottom_right_badge| or |top_left_badge| icons are not NULL, - // they will be drawn on top of the icon. + // If one of the |bottom_right_badge| or |top_left_badge| or + // |bottom_left_badge| icons are not NULL, they will be drawn on top of the + // icon. static SkBitmap IconForDisplay(const SkBitmap* icon, const SkBitmap* bottom_right_badge, - const SkBitmap* top_left_badge); + const SkBitmap* top_left_badge, + const SkBitmap* bottom_left_badge); protected: - virtual bool IsBrowserMode() const = 0; virtual gfx::NativeWindow GetNativeWindow() const = 0; virtual void OpenButtonOptions() = 0; virtual bool ShouldOpenButtonOptions() const = 0; @@ -168,58 +264,11 @@ class NetworkMenu : public views::ViewMenuDelegate, void UpdateMenu(); private: - enum MenuItemFlags { - FLAG_DISABLED = 1 << 0, - FLAG_TOGGLE_ETHERNET = 1 << 1, - FLAG_TOGGLE_WIFI = 1 << 2, - FLAG_TOGGLE_CELLULAR = 1 << 3, - FLAG_TOGGLE_OFFLINE = 1 << 4, - FLAG_ASSOCIATED = 1 << 5, - FLAG_ETHERNET = 1 << 6, - FLAG_WIFI = 1 << 7, - FLAG_CELLULAR = 1 << 8, - FLAG_OPTIONS = 1 << 9, - FLAG_OTHER_WIFI_NETWORK = 1 << 10, - FLAG_OTHER_CELLULAR_NETWORK = 1 << 11, - }; - - struct MenuItem { - MenuItem() - : type(ui::MenuModel::TYPE_SEPARATOR), - flags(0) {} - MenuItem(ui::MenuModel::ItemType type, string16 label, SkBitmap icon, - const std::string& wireless_path, int flags) - : type(type), - label(label), - icon(icon), - wireless_path(wireless_path), - flags(flags) {} - - ui::MenuModel::ItemType type; - string16 label; - SkBitmap icon; - std::string wireless_path; - int flags; - }; - typedef std::vector<MenuItem> MenuItemVector; + friend class NetworkMenuModel; // views::ViewMenuDelegate implementation. virtual void RunMenu(views::View* source, const gfx::Point& pt); - // Called by RunMenu to initialize our list of menu items. - void InitMenuItems(); - - // Shows network details in Web UI options window. - void ShowTabbedNetworkSettings(const Network* network) const; - - // Show a NetworkConfigView modal dialog instance. - // TODO(stevenjb): deprecate this once all of the UI is embedded in the menu. - void ShowNetworkConfigView(NetworkConfigView* view) const; - - void ActivateCellular(const CellularNetwork* cellular) const; - void ShowOtherWifi() const; - void ShowOtherCellular() const; - // Set to true if we are currently refreshing the menu. bool refreshing_menu_; @@ -239,12 +288,11 @@ class NetworkMenu : public views::ViewMenuDelegate, static SkBitmap kAnimatingImages[]; static SkBitmap kAnimatingImagesBlack[]; - // Our menu items. - MenuItemVector menu_items_; - // The network menu. scoped_ptr<views::Menu2> network_menu_; + scoped_ptr<NetworkMenuModel> main_menu_model_; + // Holds minimum width or -1 if it wasn't set up. int min_width_; diff --git a/chrome/browser/chromeos/status/network_menu_button.cc b/chrome/browser/chromeos/status/network_menu_button.cc index 422b225..c5ddd42 100644 --- a/chrome/browser/chromeos/status/network_menu_button.cc +++ b/chrome/browser/chromeos/status/network_menu_button.cc @@ -32,7 +32,8 @@ NetworkMenuButton::NetworkMenuButton(StatusAreaHost* host) NetworkMenu(), host_(host), icon_(NULL), - badge_(NULL), + right_badge_(NULL), + left_badge_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(animation_connecting_(this)) { animation_connecting_.SetThrobDuration(kThrobDuration); animation_connecting_.SetTweenType(ui::Tween::EASE_IN_OUT); @@ -116,21 +117,28 @@ void NetworkMenuButton::OnLocaleChanged() { //////////////////////////////////////////////////////////////////////////////// // NetworkMenuButton, private methods -void NetworkMenuButton::SetIconAndBadge(const SkBitmap* icon, - const SkBitmap* badge) { +void NetworkMenuButton::SetIconAndBadges(const SkBitmap* icon, + const SkBitmap* right_badge, + const SkBitmap* left_badge) { icon_ = icon; - badge_ = badge; - SetIcon(IconForDisplay(icon_, badge_)); + right_badge_ = right_badge; + left_badge_ = left_badge; + SetIcon(IconForDisplay(icon_, right_badge_, NULL /*no top_left_icon*/, + left_badge_)); } void NetworkMenuButton::SetIconOnly(const SkBitmap* icon) { icon_ = icon; - SetIcon(IconForDisplay(icon_, badge_)); + SetIcon(IconForDisplay(icon_, right_badge_, NULL /*no top_left_icon*/, + left_badge_)); } -void NetworkMenuButton::SetBadgeOnly(const SkBitmap* badge) { - badge_ = badge; - SetIcon(IconForDisplay(icon_, badge_)); +void NetworkMenuButton::SetBadgesOnly(const SkBitmap* right_badge, + const SkBitmap* left_badge) { + right_badge_ = right_badge; + left_badge_ = left_badge; + SetIcon(IconForDisplay(icon_, right_badge_, NULL /*no top_left_icon*/, + left_badge_)); } void NetworkMenuButton::SetNetworkIcon(NetworkLibrary* cros, @@ -138,8 +146,9 @@ void NetworkMenuButton::SetNetworkIcon(NetworkLibrary* cros, ResourceBundle& rb = ResourceBundle::GetSharedInstance(); if (!cros || !CrosLibrary::Get()->EnsureLoaded()) { - SetIconAndBadge(rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0), - rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_WARNING)); + SetIconAndBadges(rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0), + rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_WARNING), + NULL); SetTooltipText(UTF16ToWide(l10n_util::GetStringUTF16( IDS_STATUSBAR_NETWORK_NO_NETWORK_TOOLTIP))); return; @@ -147,8 +156,9 @@ void NetworkMenuButton::SetNetworkIcon(NetworkLibrary* cros, if (!cros->Connected() && !cros->Connecting()) { animation_connecting_.Stop(); - SetIconAndBadge(rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0), - rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_DISCONNECTED)); + SetIconAndBadges(rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0), + rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_DISCONNECTED), + NULL); SetTooltipText(UTF16ToWide(l10n_util::GetStringUTF16( IDS_STATUSBAR_NETWORK_NO_NETWORK_TOOLTIP))); return; @@ -164,10 +174,10 @@ void NetworkMenuButton::SetNetworkIcon(NetworkLibrary* cros, const WirelessNetwork* wireless = NULL; if (cros->wifi_connecting()) { wireless = cros->wifi_network(); - SetBadgeOnly(NULL); + SetBadgesOnly(NULL, NULL); } else { // cellular_connecting wireless = cros->cellular_network(); - SetBadgeOnly(BadgeForNetworkTechnology(cros->cellular_network())); + SetBadgesOnly(BadgeForNetworkTechnology(cros->cellular_network()), NULL); } SetTooltipText(UTF16ToWide(l10n_util::GetStringFUTF16( wireless->configuring() ? IDS_STATUSBAR_NETWORK_CONFIGURING_TOOLTIP @@ -178,8 +188,13 @@ void NetworkMenuButton::SetNetworkIcon(NetworkLibrary* cros, animation_connecting_.Stop(); // Only set the icon, if it is an active network that changed. if (network && network->is_active()) { + const SkBitmap* right_badge(NULL); + const SkBitmap* left_badge(NULL); + if (cros->virtual_network()) + left_badge = rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE); if (network->type() == TYPE_ETHERNET) { - SetIconAndBadge(rb.GetBitmapNamed(IDR_STATUSBAR_WIRED), NULL); + SetIconAndBadges(rb.GetBitmapNamed(IDR_STATUSBAR_WIRED), + right_badge, left_badge); SetTooltipText( UTF16ToWide(l10n_util::GetStringFUTF16( IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP, @@ -187,15 +202,17 @@ void NetworkMenuButton::SetNetworkIcon(NetworkLibrary* cros, IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET)))); } else if (network->type() == TYPE_WIFI) { const WifiNetwork* wifi = static_cast<const WifiNetwork*>(network); - SetIconAndBadge(IconForNetworkStrength(wifi, false), NULL); + SetIconAndBadges(IconForNetworkStrength(wifi, false), + right_badge, left_badge); SetTooltipText(UTF16ToWide(l10n_util::GetStringFUTF16( IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP, UTF8ToUTF16(wifi->name())))); } else if (network->type() == TYPE_CELLULAR) { const CellularNetwork* cellular = static_cast<const CellularNetwork*>(network); - SetIconAndBadge(IconForNetworkStrength(cellular, false), - BadgeForNetworkTechnology(cellular)); + right_badge = BadgeForNetworkTechnology(cellular); + SetIconAndBadges(IconForNetworkStrength(cellular, false), + right_badge, left_badge); SetTooltipText(UTF16ToWide(l10n_util::GetStringFUTF16( IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP, UTF8ToUTF16(cellular->name())))); diff --git a/chrome/browser/chromeos/status/network_menu_button.h b/chrome/browser/chromeos/status/network_menu_button.h index 77c4526..31c1275 100644 --- a/chrome/browser/chromeos/status/network_menu_button.h +++ b/chrome/browser/chromeos/status/network_menu_button.h @@ -65,9 +65,11 @@ class NetworkMenuButton : public StatusAreaButton, // NetworkLibrary::CellularDataPlanObserver implementation. virtual void OnCellularDataPlanChanged(NetworkLibrary* cros); - private: // NetworkMenu implementation: virtual bool IsBrowserMode() const; + + protected: + // NetworkMenu implementation: virtual gfx::NativeWindow GetNativeWindow() const; virtual void OpenButtonOptions(); virtual bool ShouldOpenButtonOptions() const; @@ -75,12 +77,15 @@ class NetworkMenuButton : public StatusAreaButton, // views::View virtual void OnLocaleChanged() OVERRIDE; - // Sets the icon and the badge. - void SetIconAndBadge(const SkBitmap* icon, const SkBitmap* badge); + private: + // Sets the icon and the badges (badges are at the bottom of the icon). + void SetIconAndBadges(const SkBitmap* icon, + const SkBitmap* right_badge, + const SkBitmap* left_badge); // Sets the icon only. Keep the previous badge. void SetIconOnly(const SkBitmap* icon); - // Sets the badge only. Keep the previous icon. - void SetBadgeOnly(const SkBitmap* badge); + // Sets the badges only. Keep the previous icon. + void SetBadgesOnly(const SkBitmap* right_badge, const SkBitmap* left_badge); // Set the network icon based on the status of the |network| void SetNetworkIcon(NetworkLibrary* cros, const Network* network); @@ -93,8 +98,10 @@ class NetworkMenuButton : public StatusAreaButton, // The icon showing the network strength. const SkBitmap* icon_; - // A badge icon displayed on top of the icon. - const SkBitmap* badge_; + // A badge icon displayed on top of icon, in bottom-right corner. + const SkBitmap* right_badge_; + // A badge icon displayed on top of icon, in bottom-left corner. + const SkBitmap* left_badge_; // The throb animation that does the wifi connecting animation. ui::ThrobAnimation animation_connecting_; diff --git a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc index 81c8ee5..16da1e5 100644 --- a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc +++ b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc @@ -598,7 +598,7 @@ void MobileSetupHandler::StartOTASP() { network->connected() && network->activation_state() == chromeos::ACTIVATION_STATE_ACTIVATED) { chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> - DisconnectFromWirelessNetwork(network); + DisconnectFromNetwork(network); } else { EvaluateCellularNetwork(network); } @@ -624,7 +624,7 @@ void MobileSetupHandler::DisconnectFromNetwork( DCHECK(network); LOG(INFO) << "Disconnecting from: " << network->service_path(); chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> - DisconnectFromWirelessNetwork(network); + DisconnectFromNetwork(network); // Disconnect will force networks to be reevaluated, so // we don't want to continue processing on this path anymore. evaluating_ = false; @@ -696,7 +696,7 @@ void MobileSetupHandler::ForceReconnect( // First, disconnect... LOG(INFO) << "Disconnecting from " << network->service_path(); chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> - DisconnectFromWirelessNetwork(network); + DisconnectFromNetwork(network); // Check the network state 3s after we disconnect to make sure. scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), delay); @@ -760,8 +760,7 @@ void MobileSetupHandler::EvaluateCellularNetwork( } default: { if (network->failed_or_disconnected() || - network->connection_state() == - chromeos::STATE_ACTIVATION_FAILURE) { + network->state() == chromeos::STATE_ACTIVATION_FAILURE) { new_state = (network->activation_state() == chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) ? PLAN_ACTIVATION_TRYING_OTASP : @@ -942,7 +941,7 @@ void MobileSetupHandler::EvaluateCellularNetwork( network->activation_state() == chromeos::ACTIVATION_STATE_ACTIVATING) && (network->error() == chromeos::ERROR_UNKNOWN || network->error() == chromeos::ERROR_OTASP_FAILED) && - network->connection_state() == chromeos::STATE_ACTIVATION_FAILURE) { + network->state() == chromeos::STATE_ACTIVATION_FAILURE) { LOG(WARNING) << "Activation failure detected " << network->service_path().c_str(); switch (state_) { @@ -1224,7 +1223,7 @@ bool MobileSetupHandler::GotActivationError( const char* error_code = kErrorDefault; // This is the magic for detection of errors in during activation process. - if (network->connection_state() == chromeos::STATE_FAILURE && + if (network->state() == chromeos::STATE_FAILURE && network->error() == chromeos::ERROR_AAA_FAILED) { if (network->activation_state() == chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) { @@ -1238,8 +1237,7 @@ bool MobileSetupHandler::GotActivationError( } } got_error = true; - } else if (network->connection_state() == - chromeos::STATE_ACTIVATION_FAILURE) { + } else if (network->state() == chromeos::STATE_ACTIVATION_FAILURE) { if (network->error() == chromeos::ERROR_NEED_EVDO) { if (network->activation_state() == chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc index 3be430c..3f8ad78 100644 --- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc @@ -648,6 +648,14 @@ void InternetOptionsHandler::PopulateDictionaryDetails( } else { PopulateCellularDetails(cros, cellular, &dictionary); } + } else if (type == chromeos::TYPE_VPN) { + const chromeos::VirtualNetwork* vpn = + cros->FindVirtualNetworkByPath(net->service_path()); + if (!vpn) { + LOG(WARNING) << "Cannot find network " << net->service_path(); + } else { + PopulateVPNDetails(vpn, &dictionary); + } } web_ui_->CallJavascriptFunction( @@ -724,6 +732,12 @@ void InternetOptionsHandler::PopulateCellularDetails( SetActivationButtonVisibility(cellular, dictionary); } +void InternetOptionsHandler::PopulateVPNDetails( + const chromeos::VirtualNetwork* vpn, + DictionaryValue* dictionary) { + // TODO(altimofeev): implement this. +} + void InternetOptionsHandler::SetActivationButtonVisibility( const chromeos::CellularNetwork* cellular, DictionaryValue* dictionary) { @@ -801,8 +815,7 @@ void InternetOptionsHandler::LoginToOtherCallback(const ListValue* args) { chromeos::NetworkLibrary* cros = chromeos::CrosLibrary::Get()->GetNetworkLibrary(); - cros->ConnectToWifiNetwork(sec, ssid, password, std::string(), std::string(), - true); + cros->ConnectToWifiNetwork(sec, ssid, password, std::string(), std::string()); } void InternetOptionsHandler::CreateModalPopup(views::WindowDelegate* view) { @@ -843,6 +856,8 @@ void InternetOptionsHandler::ButtonClickCallback(const ListValue* args) { HandleWifiButtonClick(service_path, command); } else if (type == chromeos::TYPE_CELLULAR) { HandleCellularButtonClick(service_path, command); + } else if (type == chromeos::TYPE_VPN) { + HandleVPNButtonClick(service_path, command); } else { NOTREACHED(); } @@ -862,7 +877,7 @@ void InternetOptionsHandler::HandleWifiButtonClick( cros->ForgetWifiNetwork(service_path); } else if (!use_settings_ui_ && service_path == kOtherNetworksFakePath) { // Other wifi networks. - CreateModalPopup(new chromeos::NetworkConfigView()); + CreateModalPopup(new chromeos::NetworkConfigView(chromeos::TYPE_WIFI)); } else if ((wifi = cros->FindWifiNetworkByPath(service_path))) { if (command == "connect") { // Connect to wifi here. Open password page if appropriate. @@ -883,7 +898,7 @@ void InternetOptionsHandler::HandleWifiButtonClick( cros->ConnectToWifiNetwork(wifi); } } else if (command == "disconnect") { - cros->DisconnectFromWirelessNetwork(wifi); + cros->DisconnectFromNetwork(wifi); } else if (command == "options") { PopulateDictionaryDetails(wifi, cros); } @@ -901,7 +916,7 @@ void InternetOptionsHandler::HandleCellularButtonClick( if (command == "connect") { cros->ConnectToCellularNetwork(cellular); } else if (command == "disconnect") { - cros->DisconnectFromWirelessNetwork(cellular); + cros->DisconnectFromNetwork(cellular); } else if (command == "activate") { Browser* browser = BrowserList::GetLastActive(); if (browser) @@ -912,6 +927,35 @@ void InternetOptionsHandler::HandleCellularButtonClick( } } +void InternetOptionsHandler::HandleVPNButtonClick( + const std::string& service_path, + const std::string& command) { + chromeos::NetworkLibrary* cros = + chromeos::CrosLibrary::Get()->GetNetworkLibrary(); + chromeos::VirtualNetwork* network = NULL; + // TODO(altimofeev): verify if service_path in condition is correct. + if (!use_settings_ui_ && service_path == kOtherNetworksFakePath) { + // Other VPN networks. + CreateModalPopup(new chromeos::NetworkConfigView(chromeos::TYPE_VPN)); + } else if ((network = cros->FindVirtualNetworkByPath(service_path))) { + if (command == "connect") { + // Connect to VPN here. Open password page if appropriate. + if (network->NeedMoreInfoToConnect()) { + if (use_settings_ui_) { + // TODO(altimofeev): implement this. + } else { + CreateModalPopup(new chromeos::NetworkConfigView(network)); + } + } else { + cros->ConnectToVirtualNetwork(network); + } + } else if (command == "disconnect") { + cros->DisconnectFromNetwork(network); + } else if (command == "options") { + PopulateDictionaryDetails(network, cros); + } + } +} void InternetOptionsHandler::RefreshCellularPlanCallback( const ListValue* args) { std::string service_path; @@ -1000,13 +1044,16 @@ ListValue* InternetOptionsHandler::GetWiredList() { const chromeos::EthernetNetwork* ethernet_network = cros->ethernet_network(); const SkBitmap* icon = rb.GetBitmapNamed(IDR_STATUSBAR_WIRED_BLACK); - const SkBitmap* badge = !ethernet_network || + const SkBitmap* bottom_right_badge = !ethernet_network || (!ethernet_network->connecting() && !ethernet_network->connected()) ? rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_DISCONNECTED) : NULL; + const SkBitmap* bottom_left_badge = + chromeos::NetworkMenu::BadgeForPrivateNetworkStatus(ethernet_network); if (ethernet_network) { list->Append(GetNetwork( ethernet_network->service_path(), - chromeos::NetworkMenu::IconForDisplay(icon, badge), + chromeos::NetworkMenu::IconForDisplay(icon, bottom_right_badge, NULL, + bottom_left_badge), l10n_util::GetStringUTF8(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET), ethernet_network->connecting(), ethernet_network->connected(), @@ -1026,16 +1073,24 @@ ListValue* InternetOptionsHandler::GetWirelessList() { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); ListValue* list = new ListValue(); + const chromeos::Network* active_network = cros->active_network(); + bool has_vpn = active_network && cros->virtual_network(); + bool vpn_on_wireless = has_vpn && + active_network->type() == chromeos::TYPE_WIFI; const chromeos::WifiNetworkVector& wifi_networks = cros->wifi_networks(); for (chromeos::WifiNetworkVector::const_iterator it = wifi_networks.begin(); it != wifi_networks.end(); ++it) { const SkBitmap* icon = chromeos::NetworkMenu::IconForNetworkStrength(*it, true); - const SkBitmap* badge = (*it)->encrypted() ? + const SkBitmap* bottom_right_badge = (*it)->encrypted() ? rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE) : NULL; + const SkBitmap* bottom_left_badge = + vpn_on_wireless && active_network == (*it) ? + chromeos::NetworkMenu::BadgeForPrivateNetworkStatus(NULL) : NULL; list->Append(GetNetwork( (*it)->service_path(), - chromeos::NetworkMenu::IconForDisplay(icon, badge), + chromeos::NetworkMenu::IconForDisplay(icon, bottom_right_badge, NULL, + bottom_left_badge), (*it)->name(), (*it)->connecting(), (*it)->connected(), @@ -1061,19 +1116,25 @@ ListValue* InternetOptionsHandler::GetWirelessList() { false)); } + bool vpn_on_cellular = has_vpn && + active_network->type() == chromeos::TYPE_CELLULAR; const chromeos::CellularNetworkVector cellular_networks = cros->cellular_networks(); for (chromeos::CellularNetworkVector::const_iterator it = cellular_networks.begin(); it != cellular_networks.end(); ++it) { const SkBitmap* icon = chromeos::NetworkMenu::IconForNetworkStrength(*it, true); - const SkBitmap* badge = + const SkBitmap* bottom_right_badge = chromeos::NetworkMenu::BadgeForNetworkTechnology(*it); const SkBitmap* roaming_badge = chromeos::NetworkMenu::BadgeForRoamingStatus(*it); + const SkBitmap* bottom_left_badge = + vpn_on_cellular && active_network == (*it) ? + chromeos::NetworkMenu::BadgeForPrivateNetworkStatus(NULL) : NULL; list->Append(GetNetwork( (*it)->service_path(), - chromeos::NetworkMenu::IconForDisplay(icon, badge, roaming_badge), + chromeos::NetworkMenu::IconForDisplay(icon, bottom_right_badge, + roaming_badge, bottom_left_badge), (*it)->name(), (*it)->connecting(), (*it)->connected(), @@ -1101,6 +1162,9 @@ ListValue* InternetOptionsHandler::GetRememberedList() { cros->remembered_wifi_networks(); const chromeos::WifiNetworkVector& wifi_networks = cros->wifi_networks(); + const chromeos::Network* active_network = cros->active_network(); + bool vpn_on_wireless = active_network && cros->virtual_network() && + active_network->type() == chromeos::TYPE_WIFI; // The remembered networks from libcros/flimflam don't include the signal // strength, so fall back to the detected networks for this data. We @@ -1130,11 +1194,15 @@ ListValue* InternetOptionsHandler::GetRememberedList() { // Place the secure badge on the icon if the remembered network is // encrypted (the matching detected network, if any, will have the same // encrypted property by definition). - const SkBitmap* badge = wifi->encrypted() ? + const SkBitmap* bottom_right_badge = wifi->encrypted() ? rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE) : NULL; + const SkBitmap* bottom_left_badge = + vpn_on_wireless && active_network == wifi ? + chromeos::NetworkMenu::BadgeForPrivateNetworkStatus(NULL) : NULL; list->Append(GetNetwork( wifi->service_path(), - chromeos::NetworkMenu::IconForDisplay(icon, badge), + chromeos::NetworkMenu::IconForDisplay(icon, bottom_right_badge, NULL, + bottom_left_badge), wifi->name(), wifi->connecting(), wifi->connected(), diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h index dcaf218..a4bdb56 100644 --- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h +++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h @@ -63,6 +63,8 @@ class InternetOptionsHandler const std::string& command); void HandleCellularButtonClick(const std::string& service_path, const std::string& command); + void HandleVPNButtonClick(const std::string& service_path, + const std::string& command); // Initiates cellular plan data refresh. The results from libcros will be // passed through CellularDataPlanChanged() callback method. @@ -94,6 +96,8 @@ class InternetOptionsHandler void PopulateCellularDetails(chromeos::NetworkLibrary* cros, const chromeos::CellularNetwork* cellular, DictionaryValue* dictionary); + void PopulateVPNDetails(const chromeos::VirtualNetwork* vpn, + DictionaryValue* dictionary); // Converts CellularDataPlan structure into dictionary for JS. Formats plan // settings into human readable texts. diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 072ae9d..c2312ae 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -638,6 +638,8 @@ 'browser/chromeos/options/wifi_config_model.h', 'browser/chromeos/options/wifi_config_view.cc', 'browser/chromeos/options/wifi_config_view.h', + 'browser/chromeos/options/vpn_config_view.cc', + 'browser/chromeos/options/vpn_config_view.h', 'browser/chromeos/panels/panel_scroller.cc', 'browser/chromeos/panels/panel_scroller.h', 'browser/chromeos/panels/panel_scroller_container.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 83e9322..59604c6 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -1091,6 +1091,9 @@ const char kEnableDevicePolicy[] = "enable-device-policy"; // client-side certificates. const char kEnableExperimentalEap[] = "enable-experimental-eap"; +// Enables VPN support on ChromeOS. +const char kEnableVPN[] = "enable-vpn"; + // Enable the redirection of viewable document requests to the Google // Document Viewer. const char kEnableGView[] = "enable-gview"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 248f0b8..aa51a62 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -302,6 +302,7 @@ extern const char kWinHttpProxyResolver[]; extern const char kDOMLogin[]; extern const char kEnableDevicePolicy[]; extern const char kEnableExperimentalEap[]; +extern const char kEnableVPN[]; extern const char kEnableGView[]; extern const char kEnableLoginImages[]; extern const char kLoginManager[]; |