Android activity to add a network, and all associated code for dealing
[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.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.net.ConnectivityManager;
27 import android.net.NetworkInfo;
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.ImageView;
33 import android.widget.TextView;
34
35 import com.google.zxing.client.android.Intents;
36 import com.google.zxing.client.android.R;
37 import com.google.zxing.client.android.wifi.Killer;
38 import com.google.zxing.client.android.wifi.NetworkUtil;
39 import com.google.zxing.client.android.wifi.NetworkSetting;
40
41 /**
42  * A new activity showing the progress of Wifi connection
43  * @author Vikram Aggarwal
44  *
45  */
46 public class WifiActivity extends Activity  {
47   public static enum NetworkType {
48     NETWORK_WEP, NETWORK_WPA,
49   }
50
51   /**
52    * Get a broadcast when the network is connected, and kill the activity.
53    */
54   class ConnectedReceiver extends BroadcastReceiver {
55     Activity parent = null;
56     public ConnectedReceiver(WifiActivity wifiActivity) {
57       parent = wifiActivity;
58     }
59
60     @Override
61     public void onReceive(Context context, Intent intent) {
62       if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)){
63         ConnectivityManager con = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
64         NetworkInfo[] s = con.getAllNetworkInfo();
65         for (NetworkInfo i : s){
66           if (i.getTypeName().contentEquals("WIFI")){
67             NetworkInfo.State state = i.getState();
68             if (state == NetworkInfo.State.CONNECTED){
69               statusT.setText("Connected!");
70               Killer delay_kill = new Killer(parent);
71               delay_kill.run();
72             }
73           }
74         }
75       }
76     }
77   }
78
79   private static final String tag = "NetworkActivity";
80   WifiManager mWifiManager = null;
81   TextView statusT = null;
82   ImageView statusI = null;
83   ConnectedReceiver rec = null;
84   boolean debug = true;
85
86   private int changeNetwork(NetworkSetting setting) {
87     // If the password is empty, this is an unencrypted network
88     if (setting.getPassword() == null || setting.getPassword() == "") {
89       return changeNetworkUnEncrypted(setting);
90     }
91     if (setting.getNetworkType() == NetworkType.NETWORK_WPA) {
92       return changeNetworkWPA(setting); 
93     } else {
94       return changeNetworkWEP(setting);
95     }
96   }
97
98   private WifiConfiguration changeNetworkCommon(NetworkSetting input){
99     statusT.setText("Creating settings...");
100     if (debug) {
101       Log.d(tag, "adding new configuration: \nSSID: " + input.getSsid() + "\nPassword: \""
102           + input.getPassword() + "\"\nType: " + input.getNetworkType());
103     }
104     WifiConfiguration config = new WifiConfiguration();
105
106     config.allowedAuthAlgorithms.clear();
107     config.allowedGroupCiphers.clear();
108     config.allowedKeyManagement.clear();
109     config.allowedPairwiseCiphers.clear();
110     config.allowedProtocols.clear();
111
112     // Android API insists that an ascii SSID must be quoted to be correctly handled.
113     config.SSID = NetworkUtil.convertToQuotedString(input.getSsid());   
114     config.hiddenSSID = true;
115     return config;
116   }
117
118   private int requestNetworkChange(WifiConfiguration config){           
119     boolean disableOthers = false;
120     statusT.setText("Changing Network...");
121     return updateNetwork(config, disableOthers);
122   }
123
124   // Adding a WEP network
125   private int changeNetworkWEP(NetworkSetting input) {
126     WifiConfiguration config = changeNetworkCommon(input);
127     if (NetworkUtil.isHexWepKey(input.getPassword())) {
128       config.wepKeys[0] = input.getPassword();
129     } else {
130       config.wepKeys[0] = NetworkUtil.convertToQuotedString(input.getPassword());
131     }
132     config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
133     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
134     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
135     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
136     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
137     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
138     config.wepTxKeyIndex = 0;
139     return requestNetworkChange(config);
140   }
141
142   // Adding a WPA or WPA2 network
143   private int changeNetworkWPA(NetworkSetting input) {
144     WifiConfiguration config = changeNetworkCommon(input);
145     config.preSharedKey = NetworkUtil.convertToQuotedString(input.getPassword());
146     config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
147     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
148     // For WPA
149     config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
150     // For WPA2
151     config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
152     return requestNetworkChange(config);
153   }
154
155   // Adding an open, unsecured network
156   private int changeNetworkUnEncrypted(NetworkSetting input){
157     WifiConfiguration config = changeNetworkCommon(input);
158     if (debug){
159       Log.d(tag, "Empty password prompting a simple account setting");
160     }
161     config.wepKeys[0] = "";
162     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
163     config.wepTxKeyIndex = 0;
164     return requestNetworkChange(config);
165   }
166
167   /**
168    * If the given ssid name exists in the settings, then change its password to the one given here, and save
169    * @param ssid
170    */
171   private WifiConfiguration findNetworkInExistingConfig(String ssid){
172     List <WifiConfiguration> existingConfigs = mWifiManager.getConfiguredNetworks();
173     for (int i = 0; i < existingConfigs.size(); i++){
174       if (existingConfigs.get(i).SSID.compareTo(ssid) == 0){
175         return existingConfigs.get(i);
176       }
177     }
178     return null;
179   }
180
181   @Override
182   protected void onCreate(Bundle savedInstanceState) {
183     super.onCreate(savedInstanceState);
184
185     Intent intent = getIntent();
186     if (intent == null || (!intent.getAction().equals(Intents.WifiConnect.ACTION))) {
187       finish();
188       return;
189     }
190
191     String ssid = intent.getStringExtra(Intents.WifiConnect.SSID);
192     String password = intent.getStringExtra(Intents.WifiConnect.PASSWORD);
193     String networkType = intent.getStringExtra(Intents.WifiConnect.TYPE);
194
195     // TODO(vikrama): Error checking here, to ensure ssid exists.
196     NetworkType networkT = null;
197     if (networkType.contains("WPA")) {
198       networkT = NetworkType.NETWORK_WPA;
199     }
200     else if (networkType.contains("WEP")) {
201       networkT = NetworkType.NETWORK_WEP;
202     }
203     else {
204       // Got an incorrect network type
205       finish();
206       return;
207     }
208
209     setContentView(R.layout.network);
210     statusT = (TextView) findViewById(R.id.networkStatus);
211     // This is not available before onCreate
212     mWifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
213
214     // So we know when the network changes
215     rec = new ConnectedReceiver(this);
216     registerReceiver(rec, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
217
218     if (password == null)
219       password = "";
220     if (debug) {
221       Log.d(tag, "adding new configuration: \nSSID: " + ssid + "\nPassword: \"" + password + "\"\nType: " + networkT);
222     }
223     NetworkSetting setting = new NetworkSetting(ssid, password, networkT);
224     changeNetwork(setting);
225   }
226
227   @Override
228   protected void onDestroy() {
229     super.onDestroy();
230     if (rec != null)
231       unregisterReceiver(rec);
232     rec = null;
233   }
234
235   /**
236    * Update the network: either create a new network or modify an existing network
237    * @param config: the new network configuration
238    * @param disableOthers: true if other networks must be disabled
239    * @return network ID of the connected network.
240    */
241   private int updateNetwork(WifiConfiguration config, boolean disableOthers){
242     WifiConfiguration existing = findNetworkInExistingConfig(config.SSID);
243     int networkId;
244     if (existing == null){
245       statusT.setText("Creating network...");
246       networkId = mWifiManager.addNetwork(config);
247     } else {
248       statusT.setText("Modifying network...");
249       networkId = mWifiManager.updateNetwork(config);
250     }
251     if (networkId == -1){
252       return networkId;
253     }
254     if (!mWifiManager.enableNetwork(networkId, disableOthers)) {
255       return -1;
256     }
257     mWifiManager.saveConfiguration();
258     return networkId;
259   }
260 }