1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.compatibility.common.util; 18 19 import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE; 20 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 21 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.net.ProxyInfo; 27 import android.net.Uri; 28 import android.net.wifi.WifiConfiguration; 29 import android.net.wifi.WifiManager; 30 import android.text.TextUtils; 31 import android.util.Log; 32 33 import java.util.List; 34 import java.util.concurrent.CountDownLatch; 35 import java.util.concurrent.TimeUnit; 36 37 /** 38 * A simple activity to create and manage wifi configurations. 39 */ 40 public class WifiConfigCreator { 41 public static final String ACTION_CREATE_WIFI_CONFIG = 42 "com.android.compatibility.common.util.CREATE_WIFI_CONFIG"; 43 public static final String ACTION_UPDATE_WIFI_CONFIG = 44 "com.android.compatibility.common.util.UPDATE_WIFI_CONFIG"; 45 public static final String ACTION_REMOVE_WIFI_CONFIG = 46 "com.android.compatibility.common.util.REMOVE_WIFI_CONFIG"; 47 public static final String EXTRA_NETID = "extra-netid"; 48 public static final String EXTRA_SSID = "extra-ssid"; 49 public static final String EXTRA_SECURITY_TYPE = "extra-security-type"; 50 public static final String EXTRA_PASSWORD = "extra-password"; 51 52 public static final int SECURITY_TYPE_NONE = 1; 53 public static final int SECURITY_TYPE_WPA = 2; 54 public static final int SECURITY_TYPE_WEP = 3; 55 56 private static final String TAG = "WifiConfigCreator"; 57 58 private static final long ENABLE_WIFI_WAIT_SEC = 10L; 59 60 private final Context mContext; 61 private final WifiManager mWifiManager; 62 63 public WifiConfigCreator(Context context) { 64 mContext = context; 65 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 66 } 67 68 /** 69 * Adds a new WiFi network. 70 * @return network id or -1 in case of error 71 */ 72 public int addNetwork(String ssid, boolean hidden, int securityType, 73 String password) throws InterruptedException, SecurityException { 74 checkAndEnableWifi(); 75 76 WifiConfiguration wifiConf = createConfig(ssid, hidden, securityType, password); 77 78 int netId = mWifiManager.addNetwork(wifiConf); 79 80 if (netId != -1) { 81 mWifiManager.enableNetwork(netId, true); 82 } else { 83 Log.w(TAG, "Unable to add SSID '" + ssid + "': netId = " + netId); 84 } 85 return netId; 86 } 87 88 /** 89 * Adds a new wifiConfiguration with OPEN security type, and the given pacProxy 90 * verifies that the proxy is added by getting the configuration back, and checking it. 91 * @return returns the PAC proxy URL after adding the network and getting it from WifiManager 92 * @throws IllegalStateException if any of the WifiManager operations fail 93 */ 94 public String addHttpProxyNetworkVerifyAndRemove(String ssid, String pacProxyUrl) 95 throws IllegalStateException { 96 String retrievedPacProxyUrl = null; 97 int netId = -1; 98 try { 99 WifiConfiguration conf = createConfig(ssid, false, SECURITY_TYPE_NONE, null); 100 if (pacProxyUrl != null) { 101 conf.setHttpProxy(ProxyInfo.buildPacProxy(Uri.parse(pacProxyUrl))); 102 } 103 netId = mWifiManager.addNetwork(conf); 104 if (netId == -1) { 105 throw new IllegalStateException("Failed to addNetwork: " + ssid); 106 } 107 for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) { 108 if (w.SSID.equals(ssid)) { 109 conf = w; 110 break; 111 } 112 } 113 if (conf == null) { 114 throw new IllegalStateException("Failed to get WifiConfiguration for: " + ssid); 115 } 116 Uri pacProxyFileUri = null; 117 ProxyInfo httpProxy = conf.getHttpProxy(); 118 if (httpProxy != null) pacProxyFileUri = httpProxy.getPacFileUrl(); 119 if (pacProxyFileUri != null) { 120 retrievedPacProxyUrl = conf.getHttpProxy().getPacFileUrl().toString(); 121 } 122 if (!mWifiManager.removeNetwork(netId)) { 123 throw new IllegalStateException("Failed to remove WifiConfiguration: " + ssid); 124 } 125 } finally { 126 mWifiManager.removeNetwork(netId); 127 } 128 return retrievedPacProxyUrl; 129 } 130 131 /** 132 * Updates a new WiFi network. 133 * @return network id (may differ from original) or -1 in case of error 134 */ 135 public int updateNetwork(WifiConfiguration wifiConf, String ssid, boolean hidden, 136 int securityType, String password) throws InterruptedException, SecurityException { 137 checkAndEnableWifi(); 138 if (wifiConf == null) { 139 return -1; 140 } 141 142 WifiConfiguration conf = createConfig(ssid, hidden, securityType, password); 143 conf.networkId = wifiConf.networkId; 144 145 int newNetId = mWifiManager.updateNetwork(conf); 146 147 if (newNetId != -1) { 148 mWifiManager.saveConfiguration(); 149 mWifiManager.enableNetwork(newNetId, true); 150 } else { 151 Log.w(TAG, "Unable to update SSID '" + ssid + "': netId = " + newNetId); 152 } 153 return newNetId; 154 } 155 156 /** 157 * Updates a new WiFi network. 158 * @return network id (may differ from original) or -1 in case of error 159 */ 160 public int updateNetwork(int netId, String ssid, boolean hidden, 161 int securityType, String password) throws InterruptedException, SecurityException { 162 checkAndEnableWifi(); 163 164 WifiConfiguration wifiConf = null; 165 List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); 166 for (WifiConfiguration config : configs) { 167 if (config.networkId == netId) { 168 wifiConf = config; 169 break; 170 } 171 } 172 return updateNetwork(wifiConf, ssid, hidden, securityType, password); 173 } 174 175 public boolean removeNetwork(int netId) { 176 return mWifiManager.removeNetwork(netId); 177 } 178 179 /** 180 * Creates a WifiConfiguration set up according to given parameters 181 * @param ssid SSID of the network 182 * @param hidden Is SSID not broadcast? 183 * @param securityType One of {@link #SECURITY_TYPE_NONE}, {@link #SECURITY_TYPE_WPA} or 184 * {@link #SECURITY_TYPE_WEP} 185 * @param password Password for WPA or WEP 186 * @return Created configuration object 187 */ 188 private WifiConfiguration createConfig(String ssid, boolean hidden, int securityType, 189 String password) { 190 WifiConfiguration wifiConf = new WifiConfiguration(); 191 if (!TextUtils.isEmpty(ssid)) { 192 wifiConf.SSID = '"' + ssid + '"'; 193 } 194 wifiConf.status = WifiConfiguration.Status.ENABLED; 195 wifiConf.hiddenSSID = hidden; 196 switch (securityType) { 197 case SECURITY_TYPE_NONE: 198 wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 199 break; 200 case SECURITY_TYPE_WPA: 201 updateForWPAConfiguration(wifiConf, password); 202 break; 203 case SECURITY_TYPE_WEP: 204 updateForWEPConfiguration(wifiConf, password); 205 break; 206 } 207 return wifiConf; 208 } 209 210 private void updateForWPAConfiguration(WifiConfiguration wifiConf, String wifiPassword) { 211 wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); 212 if (!TextUtils.isEmpty(wifiPassword)) { 213 wifiConf.preSharedKey = '"' + wifiPassword + '"'; 214 } 215 } 216 217 private void updateForWEPConfiguration(WifiConfiguration wifiConf, String password) { 218 wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 219 wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); 220 wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 221 if (!TextUtils.isEmpty(password)) { 222 int length = password.length(); 223 if ((length == 10 || length == 26 224 || length == 58) && password.matches("[0-9A-Fa-f]*")) { 225 wifiConf.wepKeys[0] = password; 226 } else { 227 wifiConf.wepKeys[0] = '"' + password + '"'; 228 } 229 wifiConf.wepTxKeyIndex = 0; 230 } 231 } 232 233 private void checkAndEnableWifi() throws InterruptedException { 234 final CountDownLatch enabledLatch = new CountDownLatch(1); 235 236 // Register a change receiver first to pick up events between isEnabled and setEnabled 237 final BroadcastReceiver watcher = new BroadcastReceiver() { 238 @Override 239 public void onReceive(Context context, Intent intent) { 240 if (intent.getIntExtra(EXTRA_WIFI_STATE, -1) == WIFI_STATE_ENABLED) { 241 enabledLatch.countDown(); 242 } 243 } 244 }; 245 246 mContext.registerReceiver(watcher, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); 247 try { 248 // In case wifi is not already enabled, wait for it to come up 249 if (!mWifiManager.isWifiEnabled()) { 250 mWifiManager.setWifiEnabled(true); 251 enabledLatch.await(ENABLE_WIFI_WAIT_SEC, TimeUnit.SECONDS); 252 } 253 } finally { 254 mContext.unregisterReceiver(watcher); 255 } 256 } 257 } 258 259