b86fed0a93e88e992873ee7ffe09a8c6811fe960
[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.app.AlertDialog;
23 import android.content.ActivityNotFoundException;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.net.ConnectivityManager;
27 import android.net.Uri;
28 import android.net.wifi.WifiConfiguration;
29 import android.net.wifi.WifiManager;
30 import android.os.Bundle;
31 import android.util.Log;
32 import android.widget.TextView;
33
34 import com.google.zxing.client.android.Intents;
35 import com.google.zxing.client.android.R;
36
37 /**
38  * A new activity showing the progress of Wifi connection
39  *
40  * TODO(viki): Tell the user when the network is not available here
41  * TODO(viki): Incorrect password, could not connect, give an error
42  * 
43  * @author Vikram Aggarwal
44  */
45 public class WifiActivity extends Activity  {
46
47   private static final String TAG = WifiActivity.class.getSimpleName();
48
49   private WifiManager wifiManager;
50   private TextView statusView;
51   private ConnectedReceiver connectedReceiver;
52
53   public enum NetworkType {
54     NETWORK_WEP, NETWORK_WPA, NETWORK_NOPASS, NETWORK_INVALID,
55   }
56
57   private int changeNetwork(NetworkSetting setting) {
58     // All the ways this can be wrong:
59
60     // If the SSID is empty, throw an error and return
61     if (setting.getSsid() == null || setting.getSsid().length() == 0) {
62       return doError(R.string.wifi_ssid_missing);
63     }
64     // If the network type is invalid
65     if (setting.getNetworkType() == NetworkType.NETWORK_INVALID){
66       return doError(R.string.wifi_type_incorrect);
67     }
68
69     // If the password is empty, this is an unencrypted network
70     if (setting.getPassword() == null || setting.getPassword().length() == 0 ||
71         setting.getNetworkType() == null ||
72         setting.getNetworkType() == NetworkType.NETWORK_NOPASS) {
73       return changeNetworkUnEncrypted(setting);
74     }
75     if (setting.getNetworkType() == NetworkType.NETWORK_WPA) {
76       return changeNetworkWPA(setting);
77     } else {
78       return changeNetworkWEP(setting);
79     }
80   }
81
82   private int doError(int resource_string) {
83     statusView.setText(resource_string);
84     return -1;
85   }
86
87   private WifiConfiguration changeNetworkCommon(NetworkSetting input){
88     statusView.setText("Creating settings...");
89     Log.d(TAG, "Adding new configuration: \nSSID: " + input.getSsid() + "\nType: " + input.getNetworkType());
90     WifiConfiguration config = new WifiConfiguration();
91
92     config.allowedAuthAlgorithms.clear();
93     config.allowedGroupCiphers.clear();
94     config.allowedKeyManagement.clear();
95     config.allowedPairwiseCiphers.clear();
96     config.allowedProtocols.clear();
97
98     // Android API insists that an ascii SSID must be quoted to be correctly handled.
99     config.SSID = NetworkUtil.convertToQuotedString(input.getSsid());
100     config.hiddenSSID = true;
101     return config;
102   }
103
104   private int requestNetworkChange(WifiConfiguration config){
105     statusView.setText(R.string.wifi_changing_network);
106     return updateNetwork(config, false);
107   }
108
109   // Adding a WEP network
110   private int changeNetworkWEP(NetworkSetting input) {
111     WifiConfiguration config = changeNetworkCommon(input);
112     if (NetworkUtil.isHexWepKey(input.getPassword())) {
113       config.wepKeys[0] = input.getPassword();
114     } else {
115       config.wepKeys[0] = NetworkUtil.convertToQuotedString(input.getPassword());
116     }
117     config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
118     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
119     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
120     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
121     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
122     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
123     config.wepTxKeyIndex = 0;
124     return requestNetworkChange(config);
125   }
126
127   // Adding a WPA or WPA2 network
128   private int changeNetworkWPA(NetworkSetting input) {
129     WifiConfiguration config = changeNetworkCommon(input);
130     config.preSharedKey = NetworkUtil.convertToQuotedString(input.getPassword());
131     config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
132     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
133     // For WPA
134     config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
135     // For WPA2
136     config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
137     return requestNetworkChange(config);
138   }
139
140   // Adding an open, unsecured network
141   private int changeNetworkUnEncrypted(NetworkSetting input){
142     WifiConfiguration config = changeNetworkCommon(input);
143     Log.d(TAG, "Empty password prompting a simple account setting");
144     config.wepKeys[0] = "";
145     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
146     config.wepTxKeyIndex = 0;
147     return requestNetworkChange(config);
148   }
149
150   /**
151    * If the given ssid name exists in the settings, then change its password to the one given here, and save
152    * @param ssid
153    */
154   private WifiConfiguration findNetworkInExistingConfig(String ssid){
155     List <WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
156     for (WifiConfiguration existingConfig : existingConfigs) {
157       if (existingConfig.SSID.equals(ssid)) {
158         return existingConfig;
159       }
160     }
161     return null;
162   }
163
164   @Override
165   protected void onCreate(Bundle savedInstanceState) {
166     super.onCreate(savedInstanceState);
167
168     Intent intent = getIntent();
169     if (intent == null || (!intent.getAction().equals(Intents.WifiConnect.ACTION))) {
170       finish();
171       return;
172     }
173
174     String ssid = intent.getStringExtra(Intents.WifiConnect.SSID);
175     String password = intent.getStringExtra(Intents.WifiConnect.PASSWORD);
176     String networkType = intent.getStringExtra(Intents.WifiConnect.TYPE);
177     setContentView(R.layout.network);
178     statusView = (TextView) findViewById(R.id.networkStatus);
179
180     // TODO(vikrama): Error checking here, to ensure ssid exists.
181     NetworkType networkT;
182     if (networkType.equals("WPA")) {
183       networkT = NetworkType.NETWORK_WPA;
184     } else if (networkType.equals("WEP")) {
185       networkT = NetworkType.NETWORK_WEP;
186     } else if (networkType.equals("nopass")) {
187      networkT = NetworkType.NETWORK_NOPASS;
188     } else {
189       // Got an incorrect network type.  Give an error
190       doError(R.string.wifi_type_incorrect);
191       return;
192     }
193
194     // This is not available before onCreate
195     wifiManager = (WifiManager) this.getSystemService(WIFI_SERVICE);
196
197     // So we know when the network changes
198     connectedReceiver = new ConnectedReceiver(this, statusView);
199     registerReceiver(connectedReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
200
201     if (password == null) {
202       password = "";
203     }
204     Log.d(TAG, "Adding new configuration: \nSSID: " + ssid + "Type: " + networkT);
205     NetworkSetting setting = new NetworkSetting(ssid, password, networkT);
206     changeNetwork(setting);
207   }
208
209   @Override
210   protected void onDestroy() {
211     if (connectedReceiver != null) {
212       unregisterReceiver(connectedReceiver);
213       connectedReceiver = null;
214     }
215     super.onDestroy();
216   }
217
218   /**
219    * Update the network: either create a new network or modify an existing network
220    * @param config the new network configuration
221    * @param disableOthers true if other networks must be disabled
222    * @return network ID of the connected network.
223    */
224   private int updateNetwork(WifiConfiguration config, boolean disableOthers){
225     int networkId;
226     if (findNetworkInExistingConfig(config.SSID) == null){
227       statusView.setText(R.string.wifi_creating_network);
228       networkId = wifiManager.addNetwork(config);
229     } else {
230       statusView.setText(R.string.wifi_modifying_network);
231       networkId = wifiManager.updateNetwork(config);
232     }
233     if (networkId == -1 || !wifiManager.enableNetwork(networkId, disableOthers)) {
234       return -1;
235     }
236     wifiManager.saveConfiguration();
237     return networkId;
238   }
239 }