Some error checking put in. When a new network is created and the
[zxing.git] / android / src / com / google / zxing / client / android / wifi / WifiActivity.java
index 82f43a3..f39b732 100644 (file)
@@ -33,37 +33,80 @@ import com.google.zxing.client.android.R;
 
 /**
  * A new activity showing the progress of Wifi connection
- *
+ * 
  * @author Vikram Aggarwal
  */
 public class WifiActivity extends Activity  {
 
   private static final String TAG = WifiActivity.class.getSimpleName();
-
   private WifiManager wifiManager;
   private TextView statusView;
-  private ConnectedReceiver connectedReceiver;
+  private WifiReceiver wifiReceiver;
+  private boolean receiverRegistered;
+  private int networkId;
+  private static int errorCount;
+  private IntentFilter mWifiStateFilter;
+
+  static {
+    errorCount = 0;
+  }
+
+  public void gotError(){
+    final int maxErrorCount = 3;
+    errorCount++;
+    Log.d(TAG, "Encountered another error.  Errorcount = " + errorCount);
+    if (errorCount > maxErrorCount){
+      errorCount = 0;
+      doError(R.string.wifi_connect_failed);
+    }
+  }
 
   public enum NetworkType {
-    NETWORK_WEP, NETWORK_WPA,
+    NETWORK_WEP, NETWORK_WPA, NETWORK_NOPASS, NETWORK_INVALID,
   }
 
   private int changeNetwork(NetworkSetting setting) {
+    // If the SSID is empty, throw an error and return
+    if (setting.getSsid() == null || setting.getSsid().length() == 0) {
+      return doError(R.string.wifi_ssid_missing);
+    }
+    // If the network type is invalid
+    if (setting.getNetworkType() == NetworkType.NETWORK_INVALID){
+      return doError(R.string.wifi_type_incorrect);
+    }
+
     // If the password is empty, this is an unencrypted network
-    if (setting.getPassword() == null || setting.getPassword().length() == 0) {
+    if (setting.getPassword() == null || setting.getPassword().length() == 0 ||
+        setting.getNetworkType() == null ||
+        setting.getNetworkType() == NetworkType.NETWORK_NOPASS) {
       return changeNetworkUnEncrypted(setting);
     }
     if (setting.getNetworkType() == NetworkType.NETWORK_WPA) {
-      return changeNetworkWPA(setting); 
+      return changeNetworkWPA(setting);
     } else {
       return changeNetworkWEP(setting);
     }
   }
 
+  private int doError(int resource_string) {
+    statusView.setText(resource_string);
+    // Give up on the connection
+    wifiManager.disconnect();
+    if (networkId > 0) {
+      wifiManager.removeNetwork(networkId);
+      networkId = -1;
+    }
+    if (receiverRegistered) {
+      unregisterReceiver(wifiReceiver);
+      receiverRegistered = false;
+    }
+    return -1;
+  }
+
   private WifiConfiguration changeNetworkCommon(NetworkSetting input){
-    statusView.setText("Creating settings...");
+    statusView.setText(R.string.wifi_creating_network);
     Log.d(TAG, "Adding new configuration: \nSSID: " + input.getSsid() + "\nType: " + input.getNetworkType());
-    WifiConfiguration config = new WifiConfiguration();
+    final WifiConfiguration config = new WifiConfiguration();
 
     config.allowedAuthAlgorithms.clear();
     config.allowedGroupCiphers.clear();
@@ -72,23 +115,24 @@ public class WifiActivity extends Activity  {
     config.allowedProtocols.clear();
 
     // Android API insists that an ascii SSID must be quoted to be correctly handled.
-    config.SSID = NetworkUtil.convertToQuotedString(input.getSsid());  
+    config.SSID = NetworkUtil.convertToQuotedString(input.getSsid());
     config.hiddenSSID = true;
     return config;
   }
 
   private int requestNetworkChange(WifiConfiguration config){
-    statusView.setText("Changing Network...");
+    statusView.setText(R.string.wifi_changing_network);
     return updateNetwork(config, false);
   }
 
   // Adding a WEP network
   private int changeNetworkWEP(NetworkSetting input) {
-    WifiConfiguration config = changeNetworkCommon(input);
-    if (NetworkUtil.isHexWepKey(input.getPassword())) {
-      config.wepKeys[0] = input.getPassword();
+    final WifiConfiguration config = changeNetworkCommon(input);
+    final String pass = input.getPassword();
+    if (NetworkUtil.isHexWepKey(pass)) {
+      config.wepKeys[0] = pass;
     } else {
-      config.wepKeys[0] = NetworkUtil.convertToQuotedString(input.getPassword());
+      config.wepKeys[0] = NetworkUtil.convertToQuotedString(pass);
     }
     config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
@@ -102,21 +146,31 @@ public class WifiActivity extends Activity  {
 
   // Adding a WPA or WPA2 network
   private int changeNetworkWPA(NetworkSetting input) {
-    WifiConfiguration config = changeNetworkCommon(input);
-    config.preSharedKey = NetworkUtil.convertToQuotedString(input.getPassword());
+    final WifiConfiguration config = changeNetworkCommon(input);
+    final String pass = input.getPassword();
+    // Hex passwords that are 64 bits long are not to be quoted.
+    if (pass.matches("[0-9A-Fa-f]{64}")){
+      Log.d(TAG, "A 64 bit hex password entered.");
+      config.preSharedKey = pass;
+    } else {
+      Log.d(TAG, "A normal password entered: I am quoting it.");
+      config.preSharedKey = NetworkUtil.convertToQuotedString(pass);
+    }
     config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
-    config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
     // For WPA
     config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
     // For WPA2
+    config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+    config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
+    config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
     config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
     return requestNetworkChange(config);
   }
 
   // Adding an open, unsecured network
   private int changeNetworkUnEncrypted(NetworkSetting input){
-    WifiConfiguration config = changeNetworkCommon(input);
     Log.d(TAG, "Empty password prompting a simple account setting");
+    WifiConfiguration config = changeNetworkCommon(input);
     config.wepKeys[0] = "";
     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
     config.wepTxKeyIndex = 0;
@@ -128,8 +182,8 @@ public class WifiActivity extends Activity  {
    * @param ssid
    */
   private WifiConfiguration findNetworkInExistingConfig(String ssid){
-    List <WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
-    for (WifiConfiguration existingConfig : existingConfigs) {
+    final List <WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
+    for (final WifiConfiguration existingConfig : existingConfigs) {
       if (existingConfig.SSID.equals(ssid)) {
         return existingConfig;
       }
@@ -141,36 +195,45 @@ public class WifiActivity extends Activity  {
   protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
 
-    Intent intent = getIntent();
+    final Intent intent = getIntent();
     if (intent == null || (!intent.getAction().equals(Intents.WifiConnect.ACTION))) {
       finish();
       return;
     }
 
-    String ssid = intent.getStringExtra(Intents.WifiConnect.SSID);
+    final String ssid = intent.getStringExtra(Intents.WifiConnect.SSID);
     String password = intent.getStringExtra(Intents.WifiConnect.PASSWORD);
-    String networkType = intent.getStringExtra(Intents.WifiConnect.TYPE);
+    final String networkType = intent.getStringExtra(Intents.WifiConnect.TYPE);
+    setContentView(R.layout.network);
+    statusView = (TextView) findViewById(R.id.networkStatus);
 
-    // TODO(vikrama): Error checking here, to ensure ssid exists.
     NetworkType networkT;
-    if (networkType.contains("WPA")) {
+    if (networkType.equals("WPA")) {
       networkT = NetworkType.NETWORK_WPA;
-    } else if (networkType.contains("WEP")) {
+    } else if (networkType.equals("WEP")) {
       networkT = NetworkType.NETWORK_WEP;
+    } else if (networkType.equals("nopass")) {
+     networkT = NetworkType.NETWORK_NOPASS;
     } else {
-      // Got an incorrect network type
-      finish();
+      doError(R.string.wifi_type_incorrect);
       return;
     }
 
-    setContentView(R.layout.network);
-    statusView = (TextView) findViewById(R.id.networkStatus);
     // This is not available before onCreate
     wifiManager = (WifiManager) this.getSystemService(WIFI_SERVICE);
+    // Start WiFi, otherwise nothing will work
+    wifiManager.setWifiEnabled(true);
 
     // So we know when the network changes
-    connectedReceiver = new ConnectedReceiver(this, statusView);
-    registerReceiver(connectedReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+    wifiReceiver = new WifiReceiver(wifiManager, this, statusView, ssid);
+
+    // The order matters!
+    mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
+    mWifiStateFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+    mWifiStateFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+    mWifiStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+    registerReceiver(wifiReceiver, mWifiStateFilter);
+    receiverRegistered = true;
 
     if (password == null) {
       password = "";
@@ -180,11 +243,28 @@ public class WifiActivity extends Activity  {
     changeNetwork(setting);
   }
 
+  public void pause() {
+    if (receiverRegistered) {
+      unregisterReceiver(wifiReceiver);
+      receiverRegistered = false;
+    }
+  }
+
+  public void resume() {
+    if (wifiReceiver != null && mWifiStateFilter != null && !receiverRegistered) {
+      registerReceiver(wifiReceiver, mWifiStateFilter);
+      receiverRegistered = true;
+    }
+  }
+
   @Override
   protected void onDestroy() {
-    if (connectedReceiver != null) {
-      unregisterReceiver(connectedReceiver);
-      connectedReceiver = null;
+    if (wifiReceiver != null) {
+      if (receiverRegistered) {
+       unregisterReceiver(wifiReceiver);
+       receiverRegistered = false;
+      }
+      wifiReceiver = null;
     }
     super.onDestroy();
   }
@@ -196,18 +276,29 @@ public class WifiActivity extends Activity  {
    * @return network ID of the connected network.
    */
   private int updateNetwork(WifiConfiguration config, boolean disableOthers){
-    int networkId;
-    if (findNetworkInExistingConfig(config.SSID) == null){
-      statusView.setText("Creating network...");
-      networkId = wifiManager.addNetwork(config);
+    final int FAILURE = -1;
+    WifiConfiguration found = findNetworkInExistingConfig(config.SSID);
+    wifiManager.disconnect();
+    if (found == null){
+      statusView.setText(R.string.wifi_creating_network);
     } else {
-      statusView.setText("Modifying network...");
-      networkId = wifiManager.updateNetwork(config);
-    }
-    if (networkId == -1 || !wifiManager.enableNetwork(networkId, disableOthers)) {
-      return -1;
+      statusView.setText(R.string.wifi_modifying_network);
+      Log.d(TAG, "Removing network " + found.networkId);
+      wifiManager.removeNetwork(found.networkId);
+      wifiManager.saveConfiguration();
+     }
+    networkId = wifiManager.addNetwork(config);
+    Log.d(TAG, "Inserted/Modified network " + networkId);
+    if (networkId < 0)
+      return FAILURE;
+
+    // Try to disable the current network and start a new one.
+    if (!wifiManager.enableNetwork(networkId, disableOthers)) {
+      networkId = -1;
+      return FAILURE;
     }
-    wifiManager.saveConfiguration();
+    errorCount = 0;
+    wifiManager.reassociate();
     return networkId;
   }
 }
\ No newline at end of file