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;
21 import android.app.Activity;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.net.ConnectivityManager;
25 import android.net.wifi.WifiConfiguration;
26 import android.net.wifi.WifiManager;
27 import android.os.Bundle;
28 import android.util.Log;
29 import android.widget.TextView;
31 import com.google.zxing.client.android.Intents;
32 import com.google.zxing.client.android.R;
35 * A new activity showing the progress of Wifi connection
37 * @author Vikram Aggarwal
39 public class WifiActivity extends Activity {
41 private static final String TAG = WifiActivity.class.getSimpleName();
42 private WifiManager wifiManager;
43 private TextView statusView;
44 private WifiReceiver wifiReceiver;
45 private boolean receiverRegistered;
46 private int networkId;
47 private int errorCount;
48 private IntentFilter mWifiStateFilter;
50 public void gotError(){
51 final int maxErrorCount = 3;
53 Log.d(TAG, "Encountered another error. Errorcount = " + errorCount);
54 if (errorCount > maxErrorCount){
56 doError(R.string.wifi_connect_failed);
60 public enum NetworkType {
61 NETWORK_WEP, NETWORK_WPA, NETWORK_NOPASS, NETWORK_INVALID,
64 private int changeNetwork(NetworkSetting setting) {
65 // If the SSID is empty, throw an error and return
66 if (setting.getSsid() == null || setting.getSsid().length() == 0) {
67 return doError(R.string.wifi_ssid_missing);
69 // If the network type is invalid
70 if (setting.getNetworkType() == NetworkType.NETWORK_INVALID){
71 return doError(R.string.wifi_type_incorrect);
74 // If the password is empty, this is an unencrypted network
75 if (setting.getPassword() == null || setting.getPassword().length() == 0 ||
76 setting.getNetworkType() == null ||
77 setting.getNetworkType() == NetworkType.NETWORK_NOPASS) {
78 return changeNetworkUnEncrypted(setting);
80 if (setting.getNetworkType() == NetworkType.NETWORK_WPA) {
81 return changeNetworkWPA(setting);
83 return changeNetworkWEP(setting);
87 private int doError(int resource_string) {
88 statusView.setText(resource_string);
89 // Give up on the connection
90 wifiManager.disconnect();
92 wifiManager.removeNetwork(networkId);
95 if (receiverRegistered) {
96 unregisterReceiver(wifiReceiver);
97 receiverRegistered = false;
102 private WifiConfiguration changeNetworkCommon(NetworkSetting input){
103 statusView.setText(R.string.wifi_creating_network);
104 Log.d(TAG, "Adding new configuration: \nSSID: " + input.getSsid() + "\nType: " + input.getNetworkType());
105 final WifiConfiguration config = new WifiConfiguration();
107 config.allowedAuthAlgorithms.clear();
108 config.allowedGroupCiphers.clear();
109 config.allowedKeyManagement.clear();
110 config.allowedPairwiseCiphers.clear();
111 config.allowedProtocols.clear();
113 // Android API insists that an ascii SSID must be quoted to be correctly handled.
114 config.SSID = NetworkUtil.convertToQuotedString(input.getSsid());
115 config.hiddenSSID = true;
119 private int requestNetworkChange(WifiConfiguration config){
120 statusView.setText(R.string.wifi_changing_network);
121 return updateNetwork(config, false);
124 // Adding a WEP network
125 private int changeNetworkWEP(NetworkSetting input) {
126 final WifiConfiguration config = changeNetworkCommon(input);
127 final String pass = input.getPassword();
128 if (NetworkUtil.isHexWepKey(pass)) {
129 config.wepKeys[0] = pass;
131 config.wepKeys[0] = NetworkUtil.convertToQuotedString(pass);
133 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
134 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
135 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
136 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
137 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
138 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
139 config.wepTxKeyIndex = 0;
140 return requestNetworkChange(config);
143 // Adding a WPA or WPA2 network
144 private int changeNetworkWPA(NetworkSetting input) {
145 final WifiConfiguration config = changeNetworkCommon(input);
146 final String pass = input.getPassword();
147 // Hex passwords that are 64 bits long are not to be quoted.
148 if (pass.matches("[0-9A-Fa-f]{64}")){
149 Log.d(TAG, "A 64 bit hex password entered.");
150 config.preSharedKey = pass;
152 Log.d(TAG, "A normal password entered: I am quoting it.");
153 config.preSharedKey = NetworkUtil.convertToQuotedString(pass);
155 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
157 config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
159 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
160 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
161 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
162 config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
163 return requestNetworkChange(config);
166 // Adding an open, unsecured network
167 private int changeNetworkUnEncrypted(NetworkSetting input){
168 Log.d(TAG, "Empty password prompting a simple account setting");
169 WifiConfiguration config = changeNetworkCommon(input);
170 config.wepKeys[0] = "";
171 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
172 config.wepTxKeyIndex = 0;
173 return requestNetworkChange(config);
177 * If the given ssid name exists in the settings, then change its password to the one given here, and save
180 private WifiConfiguration findNetworkInExistingConfig(String ssid){
181 final List <WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
182 for (final WifiConfiguration existingConfig : existingConfigs) {
183 if (existingConfig.SSID.equals(ssid)) {
184 return existingConfig;
191 protected void onCreate(Bundle savedInstanceState) {
192 super.onCreate(savedInstanceState);
194 final Intent intent = getIntent();
195 if (intent == null || (!intent.getAction().equals(Intents.WifiConnect.ACTION))) {
200 final String ssid = intent.getStringExtra(Intents.WifiConnect.SSID);
201 String password = intent.getStringExtra(Intents.WifiConnect.PASSWORD);
202 final String networkType = intent.getStringExtra(Intents.WifiConnect.TYPE);
203 setContentView(R.layout.network);
204 statusView = (TextView) findViewById(R.id.networkStatus);
206 NetworkType networkT;
207 if (networkType.equals("WPA")) {
208 networkT = NetworkType.NETWORK_WPA;
209 } else if (networkType.equals("WEP")) {
210 networkT = NetworkType.NETWORK_WEP;
211 } else if (networkType.equals("nopass")) {
212 networkT = NetworkType.NETWORK_NOPASS;
214 doError(R.string.wifi_type_incorrect);
218 // This is not available before onCreate
219 wifiManager = (WifiManager) this.getSystemService(WIFI_SERVICE);
220 // Start WiFi, otherwise nothing will work
221 wifiManager.setWifiEnabled(true);
223 // So we know when the network changes
224 wifiReceiver = new WifiReceiver(wifiManager, this, statusView, ssid);
226 // The order matters!
227 mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
228 mWifiStateFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
229 mWifiStateFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
230 mWifiStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
231 registerReceiver(wifiReceiver, mWifiStateFilter);
232 receiverRegistered = true;
234 if (password == null) {
237 Log.d(TAG, "Adding new configuration: \nSSID: " + ssid + "Type: " + networkT);
238 NetworkSetting setting = new NetworkSetting(ssid, password, networkT);
239 changeNetwork(setting);
243 public void onPause() {
245 if (receiverRegistered) {
246 unregisterReceiver(wifiReceiver);
247 receiverRegistered = false;
252 public void onResume() {
254 if (wifiReceiver != null && mWifiStateFilter != null && !receiverRegistered) {
255 registerReceiver(wifiReceiver, mWifiStateFilter);
256 receiverRegistered = true;
261 protected void onDestroy() {
263 if (wifiReceiver != null) {
264 if (receiverRegistered) {
265 unregisterReceiver(wifiReceiver);
266 receiverRegistered = false;
274 * Update the network: either create a new network or modify an existing network
275 * @param config the new network configuration
276 * @param disableOthers true if other networks must be disabled
277 * @return network ID of the connected network.
279 private int updateNetwork(WifiConfiguration config, boolean disableOthers){
280 final int FAILURE = -1;
281 WifiConfiguration found = findNetworkInExistingConfig(config.SSID);
282 wifiManager.disconnect();
284 statusView.setText(R.string.wifi_creating_network);
286 statusView.setText(R.string.wifi_modifying_network);
287 Log.d(TAG, "Removing network " + found.networkId);
288 wifiManager.removeNetwork(found.networkId);
289 wifiManager.saveConfiguration();
291 networkId = wifiManager.addNetwork(config);
292 Log.d(TAG, "Inserted/Modified network " + networkId);
296 // Try to disable the current network and start a new one.
297 if (!wifiManager.enableNetwork(networkId, disableOthers)) {
302 wifiManager.reassociate();