OSDN Git Service

0c177b1d9675da0968f506330c658352924a0782
[android-x86/packages-apps-Settings.git] / src / com / android / settings / wifi / WifiSettings2.java
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
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.android.settings.wifi;
18
19 import com.android.settings.ProgressCategory;
20 import com.android.settings.R;
21
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.net.NetworkInfo;
28 import android.net.wifi.ScanResult;
29 import android.net.wifi.SupplicantState;
30 import android.net.wifi.WifiConfiguration;
31 import android.net.wifi.WifiConfiguration.KeyMgmt;
32 import android.net.wifi.WifiConfiguration.Status;
33 import android.net.wifi.WifiInfo;
34 import android.net.wifi.WifiManager;
35 import android.os.Bundle;
36 import android.os.Handler;
37 import android.os.Message;
38 import android.preference.CheckBoxPreference;
39 import android.preference.Preference;
40 import android.preference.PreferenceActivity;
41 import android.preference.PreferenceScreen;
42 import android.provider.Settings.Secure;
43 import android.security.Credentials;
44 import android.security.KeyStore;
45 import android.text.TextUtils;
46 import android.view.ContextMenu;
47 import android.view.ContextMenu.ContextMenuInfo;
48 import android.view.Menu;
49 import android.view.MenuItem;
50 import android.view.View;
51 import android.widget.AdapterView.AdapterContextMenuInfo;
52 import android.widget.Toast;
53
54 import java.util.ArrayList;
55 import java.util.List;
56
57 public class WifiSettings2 extends PreferenceActivity implements DialogInterface.OnClickListener {
58     private static final int MENU_ID_SCAN = Menu.FIRST;
59     private static final int MENU_ID_ADVANCED = Menu.FIRST + 1;
60     private static final int MENU_ID_CONNECT = Menu.FIRST + 2;
61     private static final int MENU_ID_FORGET = Menu.FIRST + 3;
62     private static final int MENU_ID_MODIFY = Menu.FIRST + 4;
63
64     private final IntentFilter mFilter;
65     private final BroadcastReceiver mReceiver;
66     private final Scanner mScanner;
67
68     private WifiManager mWifiManager;
69     private WifiEnabler mWifiEnabler;
70     private CheckBoxPreference mNotifyOpenNetworks;
71     private ProgressCategory mAccessPoints;
72     private Preference mAddNetwork;
73
74     private NetworkInfo.DetailedState mLastState;
75     private WifiInfo mLastInfo;
76     private int mLastPriority;
77
78     private boolean mResetNetworks = false;
79     private int mKeyStoreNetworkId = -1;
80
81     private AccessPoint mSelected;
82     private WifiDialog mDialog;
83
84     public WifiSettings2() {
85         mFilter = new IntentFilter();
86         mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
87         mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
88         mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
89         mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
90         mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
91         mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
92
93         mReceiver = new BroadcastReceiver() {
94             @Override
95             public void onReceive(Context context, Intent intent) {
96                 handleEvent(intent);
97             }
98         };
99
100         mScanner = new Scanner();
101     }
102
103     @Override
104     protected void onCreate(Bundle savedInstanceState) {
105         super.onCreate(savedInstanceState);
106
107         mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
108
109         if (getIntent().getBooleanExtra("only_access_points", false)) {
110             addPreferencesFromResource(R.xml.wifi_access_points2);
111         } else {
112             addPreferencesFromResource(R.xml.wifi_settings2);
113             mWifiEnabler = new WifiEnabler(this, mWifiManager,
114                     (CheckBoxPreference) findPreference("enable_wifi"));
115             mNotifyOpenNetworks =
116                     (CheckBoxPreference) findPreference("notify_open_networks");
117             mNotifyOpenNetworks.setChecked(Secure.getInt(getContentResolver(),
118                     Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
119         }
120
121         mAccessPoints = (ProgressCategory) findPreference("access_points");
122         mAccessPoints.setOrderingAsAdded(false);
123         mAddNetwork = findPreference("add_network");
124
125         registerForContextMenu(getListView());
126     }
127
128     @Override
129     protected void onResume() {
130         super.onResume();
131         registerReceiver(mReceiver, mFilter);
132         if (mWifiEnabler != null) {
133             mWifiEnabler.resume();
134         }
135         if (mKeyStoreNetworkId != -1 && KeyStore.getInstance().test() == KeyStore.NO_ERROR) {
136             connect(mKeyStoreNetworkId);
137         }
138         mKeyStoreNetworkId = -1;
139     }
140
141     @Override
142     protected void onPause() {
143         super.onPause();
144         unregisterReceiver(mReceiver);
145         if (mWifiEnabler != null) {
146             mWifiEnabler.pause();
147         }
148         mScanner.pause();
149         if (mDialog != null) {
150             mDialog.dismiss();
151             mDialog = null;
152         }
153         if (mResetNetworks) {
154             enableNetworks();
155         }
156     }
157
158     @Override
159     public boolean onCreateOptionsMenu(Menu menu) {
160         menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan)
161                 .setIcon(R.drawable.ic_menu_scan_network);
162         menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
163                 .setIcon(android.R.drawable.ic_menu_manage);
164         return super.onCreateOptionsMenu(menu);
165     }
166
167     @Override
168     public boolean onOptionsItemSelected(MenuItem item) {
169         switch (item.getItemId()) {
170             case MENU_ID_SCAN:
171                 mScanner.resume();
172                 return true;
173             case MENU_ID_ADVANCED:
174                 startActivity(new Intent(this, AdvancedSettings.class));
175                 return true;
176         }
177         return super.onOptionsItemSelected(item);
178     }
179
180     @Override
181     public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
182         if (info instanceof AdapterContextMenuInfo) {
183             Preference preference = (Preference) getListView().getItemAtPosition(
184                     ((AdapterContextMenuInfo) info).position);
185
186             if (preference instanceof AccessPoint) {
187                 mSelected = (AccessPoint) preference;
188                 menu.setHeaderTitle(mSelected.ssid);
189                 if (mSelected.getLevel() != -1 && mSelected.getState() == null) {
190                     menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
191                 }
192                 if (mSelected.networkId != -1) {
193                     menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
194                     if (mSelected.security != AccessPoint.SECURITY_NONE) {
195                         menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
196                     }
197                 }
198             }
199         }
200     }
201
202     @Override
203     public boolean onContextItemSelected(MenuItem item) {
204         if (mSelected == null) {
205             return super.onContextItemSelected(item);
206         }
207         switch (item.getItemId()) {
208             case MENU_ID_CONNECT:
209                 if (mSelected.networkId != -1) {
210                     if (!requireKeyStore(mSelected.getConfig())) {
211                         connect(mSelected.networkId);
212                     }
213                 } else if (mSelected.security == AccessPoint.SECURITY_NONE) {
214                     // Shortcut for open networks.
215                     WifiConfiguration config = new WifiConfiguration();
216                     config.SSID = mSelected.ssid;
217                     config.allowedKeyManagement.set(KeyMgmt.NONE);
218                     int networkId = mWifiManager.addNetwork(config);
219                     mWifiManager.enableNetwork(networkId, false);
220                     connect(networkId);
221                 } else {
222                     showDialog(mSelected, false);
223                 }
224                 return true;
225             case MENU_ID_FORGET:
226                 forget(mSelected.networkId);
227                 return true;
228             case MENU_ID_MODIFY:
229                 showDialog(mSelected, true);
230                 return true;
231         }
232         return super.onContextItemSelected(item);
233     }
234
235     @Override
236     public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
237         if (preference instanceof AccessPoint) {
238             mSelected = (AccessPoint) preference;
239             showDialog(mSelected, false);
240         } else if (preference == mAddNetwork) {
241             mSelected = null;
242             showDialog(null, true);
243         } else if (preference == mNotifyOpenNetworks) {
244             Secure.putInt(getContentResolver(),
245                     Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
246                     mNotifyOpenNetworks.isChecked() ? 1 : 0);
247         } else {
248             return super.onPreferenceTreeClick(screen, preference);
249         }
250         return true;
251     }
252
253     public void onClick(DialogInterface dialogInterface, int button) {
254         if (button == WifiDialog.BUTTON_FORGET && mSelected != null) {
255             forget(mSelected.networkId);
256         } else if (button == WifiDialog.BUTTON_SUBMIT) {
257             WifiConfiguration config = mDialog.getConfig();
258
259             if (config == null) {
260                 if (mSelected != null && !requireKeyStore(mSelected.getConfig())) {
261                     connect(mSelected.networkId);
262                 }
263             } else if (config.networkId != -1) {
264                 if (mSelected != null) {
265                     mWifiManager.updateNetwork(config);
266                     saveNetworks();
267                 }
268             } else {
269                 int networkId = mWifiManager.addNetwork(config);
270                 if (networkId != -1) {
271                     mWifiManager.enableNetwork(networkId, false);
272                     config.networkId = networkId;
273                     if (mDialog.edit || requireKeyStore(config)) {
274                         saveNetworks();
275                     } else {
276                         connect(networkId);
277                     }
278                 }
279             }
280         }
281     }
282
283     private void showDialog(AccessPoint accessPoint, boolean edit) {
284         if (mDialog != null) {
285             mDialog.dismiss();
286         }
287         mDialog = new WifiDialog(this, this, accessPoint, edit);
288         mDialog.show();
289     }
290
291     private boolean requireKeyStore(WifiConfiguration config) {
292         if (WifiDialog.requireKeyStore(config) &&
293                 KeyStore.getInstance().test() != KeyStore.NO_ERROR) {
294             mKeyStoreNetworkId = config.networkId;
295             Credentials.getInstance().unlock(this);
296             return true;
297         }
298         return false;
299     }
300
301     private void forget(int networkId) {
302         mWifiManager.removeNetwork(networkId);
303         saveNetworks();
304     }
305
306     private void connect(int networkId) {
307         if (networkId == -1) {
308             return;
309         }
310
311         // Reset the priority of each network if it goes too high.
312         if (mLastPriority > 1000000) {
313             for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {
314                 AccessPoint accessPoint = (AccessPoint) mAccessPoints.getPreference(i);
315                 if (accessPoint.networkId != -1) {
316                     WifiConfiguration config = new WifiConfiguration();
317                     config.networkId = accessPoint.networkId;
318                     config.priority = 0;
319                     mWifiManager.updateNetwork(config);
320                 }
321             }
322             mLastPriority = 0;
323         }
324
325         // Set to the highest priority and save the configuration.
326         WifiConfiguration config = new WifiConfiguration();
327         config.networkId = networkId;
328         config.priority = ++mLastPriority;
329         mWifiManager.updateNetwork(config);
330         saveNetworks();
331
332         // Connect to network by disabling others.
333         mWifiManager.enableNetwork(networkId, true);
334         mWifiManager.reconnect();
335         mResetNetworks = true;
336     }
337
338     private void enableNetworks() {
339         for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {
340             WifiConfiguration config = ((AccessPoint) mAccessPoints.getPreference(i)).getConfig();
341             if (config != null && config.status != Status.ENABLED) {
342                 mWifiManager.enableNetwork(config.networkId, false);
343             }
344         }
345         mResetNetworks = false;
346     }
347
348     private void saveNetworks() {
349         // Always save the configuration with all networks enabled.
350         enableNetworks();
351         mWifiManager.saveConfiguration();
352         updateAccessPoints();
353     }
354
355     private void updateAccessPoints() {
356         List<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
357
358         List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
359         if (configs != null) {
360             mLastPriority = 0;
361             for (WifiConfiguration config : configs) {
362                 if (config.priority > mLastPriority) {
363                     mLastPriority = config.priority;
364                 }
365
366                 // Shift the status to make enableNetworks() more efficient.
367                 if (config.status == Status.CURRENT) {
368                     config.status = Status.ENABLED;
369                 } else if (mResetNetworks && config.status == Status.DISABLED) {
370                     config.status = Status.CURRENT;
371                 }
372
373                 AccessPoint accessPoint = new AccessPoint(this, config);
374                 accessPoint.update(mLastInfo, mLastState);
375                 accessPoints.add(accessPoint);
376             }
377         }
378
379         List<ScanResult> results = mWifiManager.getScanResults();
380         if (results != null) {
381             for (ScanResult result : results) {
382                 // Ignore hidden and ad-hoc networks.
383                 if (result.SSID == null || result.SSID.length() == 0 ||
384                         result.capabilities.contains("[IBSS]")) {
385                     continue;
386                 }
387
388                 boolean found = false;
389                 for (AccessPoint accessPoint : accessPoints) {
390                     if (accessPoint.update(result)) {
391                         found = true;
392                     }
393                 }
394                 if (!found) {
395                     accessPoints.add(new AccessPoint(this, result));
396                 }
397             }
398         }
399
400         mAccessPoints.removeAll();
401         for (AccessPoint accessPoint : accessPoints) {
402             mAccessPoints.addPreference(accessPoint);
403         }
404     }
405
406     private void handleEvent(Intent intent) {
407         String action = intent.getAction();
408         if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
409             updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
410                     WifiManager.WIFI_STATE_UNKNOWN));
411         } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
412             updateAccessPoints();
413         } else if (WifiManager.NETWORK_IDS_CHANGED_ACTION.equals(action)) {
414             if (mSelected != null && mSelected.networkId != -1) {
415                 mSelected = null;
416             }
417             updateAccessPoints();
418         } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
419             updateConnectionState(WifiInfo.getDetailedStateOf((SupplicantState)
420                     intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
421         } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
422             updateConnectionState(((NetworkInfo) intent.getParcelableExtra(
423                     WifiManager.EXTRA_NETWORK_INFO)).getDetailedState());
424         } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
425             updateConnectionState(null);
426         }
427     }
428
429     private void updateConnectionState(NetworkInfo.DetailedState state) {
430         if (state == NetworkInfo.DetailedState.OBTAINING_IPADDR) {
431             mScanner.pause();
432         } else {
433             mScanner.resume();
434         }
435
436         mLastInfo = mWifiManager.getConnectionInfo();
437         if (state != null) {
438             mLastState = state;
439         }
440
441         for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {
442             ((AccessPoint) mAccessPoints.getPreference(i)).update(mLastInfo, mLastState);
443         }
444     }
445
446     private void updateWifiState(int state) {
447         if (state == WifiManager.WIFI_STATE_ENABLED) {
448             mScanner.resume();
449             updateAccessPoints();
450         } else {
451             mScanner.pause();
452             mAccessPoints.removeAll();
453         }
454     }
455
456     private class Scanner extends Handler {
457         private int mRetry = 0;
458
459         void resume() {
460             if (!hasMessages(0)) {
461                 sendEmptyMessage(0);
462             }
463         }
464
465         void pause() {
466             mRetry = 0;
467             mAccessPoints.setProgress(false);
468             removeMessages(0);
469         }
470
471         @Override
472         public void handleMessage(Message message) {
473             if (mWifiManager.startScanActive()) {
474                 mRetry = 0;
475             } else if (++mRetry >= 3) {
476                 mRetry = 0;
477                 Toast.makeText(WifiSettings2.this, R.string.wifi_fail_to_scan,
478                         Toast.LENGTH_LONG).show();
479             }
480             mAccessPoints.setProgress(mRetry != 0);
481             sendEmptyMessageDelayed(0, 6000);
482         }
483     }
484 }