2 * Copyright (C) 2010 ZXing authors
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.google.zxing.client.android.wifi;
19 import java.util.List;
20 import java.util.regex.Pattern;
22 import android.app.Activity;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.net.ConnectivityManager;
26 import android.net.wifi.WifiConfiguration;
27 import android.net.wifi.WifiManager;
28 import android.os.Bundle;
29 import android.util.Log;
30 import android.widget.TextView;
32 import com.google.zxing.client.android.Intents;
33 import com.google.zxing.client.android.R;
36 * A new activity showing the progress of Wifi connection
38 * @author Vikram Aggarwal
40 public final class WifiActivity extends Activity {
42 private static final String TAG = WifiActivity.class.getSimpleName();
44 private static final int MAX_ERROR_COUNT = 3;
45 private static final int FAILURE_NO_NETWORK_ID = -1;
46 private static final Pattern HEX_DIGITS_64 = Pattern.compile("[0-9A-Fa-f]{64}");
48 private WifiManager wifiManager;
49 private TextView statusView;
50 private WifiReceiver wifiReceiver;
51 private boolean receiverRegistered;
52 private int networkId;
53 private int errorCount;
54 private IntentFilter mWifiStateFilter;
58 Log.d(TAG, "Encountered another error. Errorcount = " + errorCount);
59 if (errorCount > MAX_ERROR_COUNT){
61 doError(R.string.wifi_connect_failed);
65 public enum NetworkType {
66 NETWORK_WEP, NETWORK_WPA, NETWORK_NOPASS, NETWORK_INVALID,
69 private int changeNetwork(NetworkSetting setting) {
70 // If the SSID is empty, throw an error and return
71 if (setting.getSsid() == null || setting.getSsid().length() == 0) {
72 return doError(R.string.wifi_ssid_missing);
74 // If the network type is invalid
75 if (setting.getNetworkType() == NetworkType.NETWORK_INVALID){
76 return doError(R.string.wifi_type_incorrect);
79 // If the password is empty, this is an unencrypted network
80 if (setting.getPassword() == null || setting.getPassword().length() == 0 ||
81 setting.getNetworkType() == null ||
82 setting.getNetworkType() == NetworkType.NETWORK_NOPASS) {
83 return changeNetworkUnEncrypted(setting);
85 if (setting.getNetworkType() == NetworkType.NETWORK_WPA) {
86 return changeNetworkWPA(setting);
88 return changeNetworkWEP(setting);
92 private int doError(int resource_string) {
93 statusView.setText(resource_string);
94 // Give up on the connection
95 wifiManager.disconnect();
97 wifiManager.removeNetwork(networkId);
100 if (receiverRegistered) {
101 unregisterReceiver(wifiReceiver);
102 receiverRegistered = false;
107 private WifiConfiguration changeNetworkCommon(NetworkSetting input){
108 statusView.setText(R.string.wifi_creating_network);
109 Log.d(TAG, "Adding new configuration: \nSSID: " + input.getSsid() + "\nType: " + input.getNetworkType());
110 WifiConfiguration config = new WifiConfiguration();
112 config.allowedAuthAlgorithms.clear();
113 config.allowedGroupCiphers.clear();
114 config.allowedKeyManagement.clear();
115 config.allowedPairwiseCiphers.clear();
116 config.allowedProtocols.clear();
118 // Android API insists that an ascii SSID must be quoted to be correctly handled.
119 config.SSID = NetworkUtil.convertToQuotedString(input.getSsid());
120 config.hiddenSSID = true;
124 private int requestNetworkChange(WifiConfiguration config){
125 statusView.setText(R.string.wifi_changing_network);
126 return updateNetwork(config, false);
129 // Adding a WEP network
130 private int changeNetworkWEP(NetworkSetting input) {
131 WifiConfiguration config = changeNetworkCommon(input);
132 String pass = input.getPassword();
133 if (NetworkUtil.isHexWepKey(pass)) {
134 config.wepKeys[0] = pass;
136 config.wepKeys[0] = NetworkUtil.convertToQuotedString(pass);
138 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
139 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
140 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
141 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
142 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
143 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
144 config.wepTxKeyIndex = 0;
145 return requestNetworkChange(config);
148 // Adding a WPA or WPA2 network
149 private int changeNetworkWPA(NetworkSetting input) {
150 WifiConfiguration config = changeNetworkCommon(input);
151 String pass = input.getPassword();
152 // Hex passwords that are 64 bits long are not to be quoted.
153 if (HEX_DIGITS_64.matcher(pass).matches()){
154 Log.d(TAG, "A 64 bit hex password entered.");
155 config.preSharedKey = pass;
157 Log.d(TAG, "A normal password entered: I am quoting it.");
158 config.preSharedKey = NetworkUtil.convertToQuotedString(pass);
160 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
162 config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
164 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
165 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
166 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
167 config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
168 return requestNetworkChange(config);
171 // Adding an open, unsecured network
172 private int changeNetworkUnEncrypted(NetworkSetting input){
173 Log.d(TAG, "Empty password prompting a simple account setting");
174 WifiConfiguration config = changeNetworkCommon(input);
175 config.wepKeys[0] = "";
176 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
177 config.wepTxKeyIndex = 0;
178 return requestNetworkChange(config);
182 * If the given ssid name exists in the settings, then change its password to the one given here, and save
185 private WifiConfiguration findNetworkInExistingConfig(String ssid){
186 List<WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
187 for (WifiConfiguration existingConfig : existingConfigs) {
188 if (existingConfig.SSID.equals(ssid)) {
189 return existingConfig;
196 protected void onCreate(Bundle savedInstanceState) {
197 super.onCreate(savedInstanceState);
199 Intent intent = getIntent();
200 if (intent == null || (!intent.getAction().equals(Intents.WifiConnect.ACTION))) {
205 String ssid = intent.getStringExtra(Intents.WifiConnect.SSID);
206 String password = intent.getStringExtra(Intents.WifiConnect.PASSWORD);
207 String networkType = intent.getStringExtra(Intents.WifiConnect.TYPE);
208 setContentView(R.layout.network);
209 statusView = (TextView) findViewById(R.id.networkStatus);
211 NetworkType networkT;
212 if (networkType.equals("WPA")) {
213 networkT = NetworkType.NETWORK_WPA;
214 } else if (networkType.equals("WEP")) {
215 networkT = NetworkType.NETWORK_WEP;
216 } else if (networkType.equals("nopass")) {
217 networkT = NetworkType.NETWORK_NOPASS;
219 doError(R.string.wifi_type_incorrect);
223 // This is not available before onCreate
224 wifiManager = (WifiManager) this.getSystemService(WIFI_SERVICE);
225 // Start WiFi, otherwise nothing will work
226 wifiManager.setWifiEnabled(true);
228 // So we know when the network changes
229 wifiReceiver = new WifiReceiver(wifiManager, this, statusView, ssid);
231 // The order matters!
232 mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
233 mWifiStateFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
234 mWifiStateFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
235 mWifiStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
236 registerReceiver(wifiReceiver, mWifiStateFilter);
237 receiverRegistered = true;
239 if (password == null) {
242 Log.d(TAG, "Adding new configuration: \nSSID: " + ssid + "Type: " + networkT);
243 NetworkSetting setting = new NetworkSetting(ssid, password, networkT);
244 changeNetwork(setting);
248 public void onPause() {
250 if (receiverRegistered) {
251 unregisterReceiver(wifiReceiver);
252 receiverRegistered = false;
257 public void onResume() {
259 if (wifiReceiver != null && mWifiStateFilter != null && !receiverRegistered) {
260 registerReceiver(wifiReceiver, mWifiStateFilter);
261 receiverRegistered = true;
266 protected void onDestroy() {
267 if (wifiReceiver != null) {
268 if (receiverRegistered) {
269 unregisterReceiver(wifiReceiver);
270 receiverRegistered = false;
278 * Update the network: either create a new network or modify an existing network
279 * @param config the new network configuration
280 * @param disableOthers true if other networks must be disabled
281 * @return network ID of the connected network.
283 private int updateNetwork(WifiConfiguration config, boolean disableOthers) {
284 WifiConfiguration found = findNetworkInExistingConfig(config.SSID);
285 wifiManager.disconnect();
287 statusView.setText(R.string.wifi_creating_network);
289 statusView.setText(R.string.wifi_modifying_network);
290 Log.d(TAG, "Removing network " + found.networkId);
291 wifiManager.removeNetwork(found.networkId);
292 wifiManager.saveConfiguration();
294 networkId = wifiManager.addNetwork(config);
295 Log.d(TAG, "Inserted/Modified network " + networkId);
297 return FAILURE_NO_NETWORK_ID;
300 // Try to disable the current network and start a new one.
301 if (!wifiManager.enableNetwork(networkId, disableOthers)) {
302 networkId = FAILURE_NO_NETWORK_ID;
303 return FAILURE_NO_NETWORK_ID;
306 wifiManager.reassociate();