Fixed: pause -> onPause, resume -> onResume
[zxing.git] / android / src / com / google / zxing / client / android / wifi / WifiActivity.java
1 /*
2  * Copyright (C) 2010 ZXing authors
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.google.zxing.client.android.wifi;
18
19 import java.util.List;
20
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;
30
31 import com.google.zxing.client.android.Intents;
32 import com.google.zxing.client.android.R;
33
34 /**
35  * A new activity showing the progress of Wifi connection
36  * 
37  * @author Vikram Aggarwal
38  */
39 public class WifiActivity extends Activity  {
40
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;
49
50   public void gotError(){
51     final int maxErrorCount = 3;
52     errorCount++;
53     Log.d(TAG, "Encountered another error.  Errorcount = " + errorCount);
54     if (errorCount > maxErrorCount){
55       errorCount = 0;
56       doError(R.string.wifi_connect_failed);
57     }
58   }
59
60   public enum NetworkType {
61     NETWORK_WEP, NETWORK_WPA, NETWORK_NOPASS, NETWORK_INVALID,
62   }
63
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);
68     }
69     // If the network type is invalid
70     if (setting.getNetworkType() == NetworkType.NETWORK_INVALID){
71       return doError(R.string.wifi_type_incorrect);
72     }
73
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);
79     }
80     if (setting.getNetworkType() == NetworkType.NETWORK_WPA) {
81       return changeNetworkWPA(setting);
82     } else {
83       return changeNetworkWEP(setting);
84     }
85   }
86
87   private int doError(int resource_string) {
88     statusView.setText(resource_string);
89     // Give up on the connection
90     wifiManager.disconnect();
91     if (networkId > 0) {
92       wifiManager.removeNetwork(networkId);
93       networkId = -1;
94     }
95     if (receiverRegistered) {
96       unregisterReceiver(wifiReceiver);
97       receiverRegistered = false;
98     }
99     return -1;
100   }
101
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();
106
107     config.allowedAuthAlgorithms.clear();
108     config.allowedGroupCiphers.clear();
109     config.allowedKeyManagement.clear();
110     config.allowedPairwiseCiphers.clear();
111     config.allowedProtocols.clear();
112
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;
116     return config;
117   }
118
119   private int requestNetworkChange(WifiConfiguration config){
120     statusView.setText(R.string.wifi_changing_network);
121     return updateNetwork(config, false);
122   }
123
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;
130     } else {
131       config.wepKeys[0] = NetworkUtil.convertToQuotedString(pass);
132     }
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);
141   }
142
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;
151     } else {
152       Log.d(TAG, "A normal password entered: I am quoting it.");
153       config.preSharedKey = NetworkUtil.convertToQuotedString(pass);
154     }
155     config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
156     // For WPA
157     config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
158     // For WPA2
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);
164   }
165
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);
174   }
175
176   /**
177    * If the given ssid name exists in the settings, then change its password to the one given here, and save
178    * @param ssid
179    */
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;
185       }
186     }
187     return null;
188   }
189
190   @Override
191   protected void onCreate(Bundle savedInstanceState) {
192     super.onCreate(savedInstanceState);
193
194     final Intent intent = getIntent();
195     if (intent == null || (!intent.getAction().equals(Intents.WifiConnect.ACTION))) {
196       finish();
197       return;
198     }
199
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);
205
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;
213     } else {
214       doError(R.string.wifi_type_incorrect);
215       return;
216     }
217
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);
222
223     // So we know when the network changes
224     wifiReceiver = new WifiReceiver(wifiManager, this, statusView, ssid);
225
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;
233
234     if (password == null) {
235       password = "";
236     }
237     Log.d(TAG, "Adding new configuration: \nSSID: " + ssid + "Type: " + networkT);
238     NetworkSetting setting = new NetworkSetting(ssid, password, networkT);
239     changeNetwork(setting);
240   }
241
242   @Override
243   public void onPause() {
244     super.onPause();
245     if (receiverRegistered) {
246       unregisterReceiver(wifiReceiver);
247       receiverRegistered = false;
248     }
249   }
250
251   @Override
252   public void onResume() {
253     super.onResume();
254     if (wifiReceiver != null && mWifiStateFilter != null && !receiverRegistered) {
255       registerReceiver(wifiReceiver, mWifiStateFilter);
256       receiverRegistered = true;
257     }
258   }
259
260   @Override
261   protected void onDestroy() {
262     super.onDestroy();
263     if (wifiReceiver != null) {
264       if (receiverRegistered) {
265         unregisterReceiver(wifiReceiver);
266         receiverRegistered = false;
267       }
268       wifiReceiver = null;
269     }
270     super.onDestroy();
271   }
272
273   /**
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.
278    */
279   private int updateNetwork(WifiConfiguration config, boolean disableOthers){
280     final int FAILURE = -1;
281     WifiConfiguration found = findNetworkInExistingConfig(config.SSID);
282     wifiManager.disconnect();
283     if (found == null){
284       statusView.setText(R.string.wifi_creating_network);
285     } else {
286       statusView.setText(R.string.wifi_modifying_network);
287       Log.d(TAG, "Removing network " + found.networkId);
288       wifiManager.removeNetwork(found.networkId);
289       wifiManager.saveConfiguration();
290      }
291     networkId = wifiManager.addNetwork(config);
292     Log.d(TAG, "Inserted/Modified network " + networkId);
293     if (networkId < 0)
294       return FAILURE;
295
296     // Try to disable the current network and start a new one.
297     if (!wifiManager.enableNetwork(networkId, disableOthers)) {
298       networkId = -1;
299       return FAILURE;
300     }
301     errorCount = 0;
302     wifiManager.reassociate();
303     return networkId;
304   }
305 }