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 android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.net.wifi.WifiConfiguration;
24 import android.net.wifi.WifiManager;
25 import android.text.TextUtils;
26 import android.util.Log;
27 
28 import java.util.concurrent.CountDownLatch;
29 import java.util.concurrent.TimeUnit;
30 import java.util.List;
31 
32 import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
33 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
34 
35 /**
36  * A simple activity to create and manage wifi configurations.
37  */
38 public class WifiConfigCreator {
39     public static final String ACTION_CREATE_WIFI_CONFIG =
40             "com.android.compatibility.common.util.CREATE_WIFI_CONFIG";
41     public static final String ACTION_UPDATE_WIFI_CONFIG =
42             "com.android.compatibility.common.util.UPDATE_WIFI_CONFIG";
43     public static final String ACTION_REMOVE_WIFI_CONFIG =
44             "com.android.compatibility.common.util.REMOVE_WIFI_CONFIG";
45     public static final String EXTRA_NETID = "extra-netid";
46     public static final String EXTRA_SSID = "extra-ssid";
47     public static final String EXTRA_SECURITY_TYPE = "extra-security-type";
48     public static final String EXTRA_PASSWORD = "extra-password";
49 
50     public static final int SECURITY_TYPE_NONE = 1;
51     public static final int SECURITY_TYPE_WPA = 2;
52     public static final int SECURITY_TYPE_WEP = 3;
53 
54     private static final String TAG = "WifiConfigCreator";
55 
56     private static final long ENABLE_WIFI_WAIT_SEC = 10L;
57 
58     private final Context mContext;
59     private final WifiManager mWifiManager;
60 
WifiConfigCreator(Context context)61     public WifiConfigCreator(Context context) {
62         mContext = context;
63         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
64     }
65 
66     /**
67      * Adds a new WiFi network.
68      * @return network id or -1 in case of error
69      */
addNetwork(String ssid, boolean hidden, int securityType, String password)70     public int addNetwork(String ssid, boolean hidden, int securityType,
71             String password) throws InterruptedException, SecurityException {
72         checkAndEnableWifi();
73 
74         WifiConfiguration wifiConf = createConfig(ssid, hidden, securityType, password);
75 
76         int netId = mWifiManager.addNetwork(wifiConf);
77 
78         if (netId != -1) {
79             mWifiManager.enableNetwork(netId, true);
80         } else {
81             Log.w(TAG, "Unable to add SSID '" + ssid + "': netId = " + netId);
82         }
83         return netId;
84     }
85 
86     /**
87      * Updates a new WiFi network.
88      * @return network id (may differ from original) or -1 in case of error
89      */
updateNetwork(WifiConfiguration wifiConf, String ssid, boolean hidden, int securityType, String password)90     public int updateNetwork(WifiConfiguration wifiConf, String ssid, boolean hidden,
91             int securityType, String password) throws InterruptedException, SecurityException {
92         checkAndEnableWifi();
93         if (wifiConf == null) {
94             return -1;
95         }
96 
97         WifiConfiguration conf = createConfig(ssid, hidden, securityType, password);
98         conf.networkId = wifiConf.networkId;
99 
100         int newNetId = mWifiManager.updateNetwork(conf);
101 
102         if (newNetId != -1) {
103             mWifiManager.saveConfiguration();
104             mWifiManager.enableNetwork(newNetId, true);
105         } else {
106             Log.w(TAG, "Unable to update SSID '" + ssid + "': netId = " + newNetId);
107         }
108         return newNetId;
109     }
110 
111     /**
112      * Updates a new WiFi network.
113      * @return network id (may differ from original) or -1 in case of error
114      */
updateNetwork(int netId, String ssid, boolean hidden, int securityType, String password)115     public int updateNetwork(int netId, String ssid, boolean hidden,
116             int securityType, String password) throws InterruptedException, SecurityException {
117         checkAndEnableWifi();
118 
119         WifiConfiguration wifiConf = null;
120         List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
121         for (WifiConfiguration config : configs) {
122             if (config.networkId == netId) {
123                 wifiConf = config;
124                 break;
125             }
126         }
127         return updateNetwork(wifiConf, ssid, hidden, securityType, password);
128     }
129 
removeNetwork(int netId)130     public boolean removeNetwork(int netId) {
131         return mWifiManager.removeNetwork(netId);
132     }
133 
134     /**
135      * Creates a WifiConfiguration set up according to given parameters
136      * @param ssid SSID of the network
137      * @param hidden Is SSID not broadcast?
138      * @param securityType One of {@link #SECURITY_TYPE_NONE}, {@link #SECURITY_TYPE_WPA} or
139      *                     {@link #SECURITY_TYPE_WEP}
140      * @param password Password for WPA or WEP
141      * @return Created configuration object
142      */
createConfig(String ssid, boolean hidden, int securityType, String password)143     private WifiConfiguration createConfig(String ssid, boolean hidden, int securityType,
144             String password) {
145         WifiConfiguration wifiConf = new WifiConfiguration();
146         if (!TextUtils.isEmpty(ssid)) {
147             wifiConf.SSID = '"' + ssid + '"';
148         }
149         wifiConf.status = WifiConfiguration.Status.ENABLED;
150         wifiConf.hiddenSSID = hidden;
151         switch (securityType) {
152             case SECURITY_TYPE_NONE:
153                 wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
154                 break;
155             case SECURITY_TYPE_WPA:
156                 updateForWPAConfiguration(wifiConf, password);
157                 break;
158             case SECURITY_TYPE_WEP:
159                 updateForWEPConfiguration(wifiConf, password);
160                 break;
161         }
162         return wifiConf;
163     }
164 
updateForWPAConfiguration(WifiConfiguration wifiConf, String wifiPassword)165     private void updateForWPAConfiguration(WifiConfiguration wifiConf, String wifiPassword) {
166         wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
167         if (!TextUtils.isEmpty(wifiPassword)) {
168             wifiConf.preSharedKey = '"' + wifiPassword + '"';
169         }
170     }
171 
updateForWEPConfiguration(WifiConfiguration wifiConf, String password)172     private void updateForWEPConfiguration(WifiConfiguration wifiConf, String password) {
173         wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
174         wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
175         wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
176         if (!TextUtils.isEmpty(password)) {
177             int length = password.length();
178             if ((length == 10 || length == 26
179                     || length == 58) && password.matches("[0-9A-Fa-f]*")) {
180                 wifiConf.wepKeys[0] = password;
181             } else {
182                 wifiConf.wepKeys[0] = '"' + password + '"';
183             }
184             wifiConf.wepTxKeyIndex = 0;
185         }
186     }
187 
checkAndEnableWifi()188     private void checkAndEnableWifi() throws InterruptedException {
189         final CountDownLatch enabledLatch = new CountDownLatch(1);
190 
191         // Register a change receiver first to pick up events between isEnabled and setEnabled
192         final BroadcastReceiver watcher = new BroadcastReceiver() {
193             @Override
194             public void onReceive(Context context, Intent intent) {
195                 if (intent.getIntExtra(EXTRA_WIFI_STATE, -1) == WIFI_STATE_ENABLED) {
196                     enabledLatch.countDown();
197                 }
198             }
199         };
200 
201         mContext.registerReceiver(watcher, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
202         try {
203             // In case wifi is not already enabled, wait for it to come up
204             if (!mWifiManager.isWifiEnabled()) {
205                 mWifiManager.setWifiEnabled(true);
206                 enabledLatch.await(ENABLE_WIFI_WAIT_SEC, TimeUnit.SECONDS);
207             }
208         } finally {
209             mContext.unregisterReceiver(watcher);
210         }
211     }
212 }
213 
214