• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 import com.android.settings.SecuritySettings;
22 
23 import android.app.Dialog;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.net.wifi.WifiManager;
27 import android.os.Bundle;
28 import android.preference.Preference;
29 import android.preference.PreferenceActivity;
30 import android.preference.PreferenceScreen;
31 import android.preference.CheckBoxPreference;
32 import android.provider.Settings;
33 import android.security.Keystore;
34 import android.util.Log;
35 import android.view.ContextMenu;
36 import android.view.Menu;
37 import android.view.MenuItem;
38 import android.view.View;
39 import android.view.ContextMenu.ContextMenuInfo;
40 import android.widget.AdapterView;
41 import android.widget.Toast;
42 import android.widget.AdapterView.AdapterContextMenuInfo;
43 
44 import java.util.Set;
45 import java.util.WeakHashMap;
46 
47 /**
48  * Settings screen for WiFi. This will be launched from the main system settings.
49  */
50 public class WifiSettings extends PreferenceActivity implements WifiLayer.Callback,
51         DialogInterface.OnDismissListener {
52 
53     private static final String TAG = "WifiSettings";
54 
55     //============================
56     // Preference/activity member variables
57     //============================
58 
59     private static final String INSTANCE_KEY_DIALOG_BUNDLE =
60             "com.android.settings.wifi.WifiSettings:dialogBundle";
61     /*
62      * We don't use Activity's dialog management because AlertDialog isn't fully
63      * able to change many of its features after it's been created, and the
64      * dialog management only creates once.
65      */
66     private Dialog mDialog;
67 
68     private static final String KEY_ADD_OTHER_NETWORK = "add_other_network";
69 
70     private static final int CONTEXT_MENU_ID_CONNECT = Menu.FIRST;
71     private static final int CONTEXT_MENU_ID_FORGET = Menu.FIRST + 1;
72     private static final int CONTEXT_MENU_ID_CHANGE_PASSWORD = Menu.FIRST + 2;
73 
74     private static final int MENU_ID_SCAN = Menu.FIRST;
75     private static final int MENU_ID_ADVANCED = Menu.FIRST + 1;
76 
77     private static final String KEY_WIFI_ENABLED = "wifi_enabled";
78     private static final String KEY_OPEN_NETWORK_NOTIFICATIONS_ENABLED =
79             "open_network_notifications_enabled";
80     private static final String KEY_ACCESS_POINTS = "access_points";
81 
82     private ProgressCategory mApCategory;
83     private CheckBoxPreference mWifiEnabled;
84     private WifiEnabler mWifiEnabler;
85     private CheckBoxPreference mOpenNetworkNotificationsEnabled;
86     private Preference mAddOtherNetwork;
87 
88     private WeakHashMap<AccessPointState, AccessPointPreference> mAps;
89 
90     private AccessPointState mResumeState = null;
91     private int mResumeMode;
92 
93     //============================
94     // Wifi member variables
95     //============================
96 
97     private WifiLayer mWifiLayer;
98 
99     //============================
100     // Activity lifecycle
101     //============================
102 
WifiSettings()103     public WifiSettings() {
104         mAps = new WeakHashMap<AccessPointState, AccessPointPreference>();
105         mWifiLayer = new WifiLayer(this, this);
106     }
107 
108     @Override
onCreate(Bundle savedInstanceState)109     protected void onCreate(Bundle savedInstanceState) {
110         super.onCreate(savedInstanceState);
111 
112         onCreatePreferences();
113         mWifiLayer.onCreate();
114 
115         onCreatedWifi();
116         mWifiLayer.onCreatedCallback();
117     }
118 
119     /**
120      * Shouldn't have any dependency on the wifi layer.
121      */
onCreatePreferences()122     private void onCreatePreferences() {
123         addPreferencesFromResource(R.xml.wifi_settings);
124 
125         final PreferenceScreen preferenceScreen = getPreferenceScreen();
126 
127         mApCategory = (ProgressCategory) preferenceScreen.findPreference(KEY_ACCESS_POINTS);
128         // We don't want the ordering to be the order preferences are added,
129         // instead we want*:
130         //   1) preferred, visible APs
131         //   2) visible APs
132         //   3) preferred, APs out of range
133         //   * this ordering logic is in AccessPointPreference's compareTo
134         mApCategory.setOrderingAsAdded(false);
135 
136         mWifiEnabled = (CheckBoxPreference) preferenceScreen.findPreference(KEY_WIFI_ENABLED);
137         mWifiEnabler = new WifiEnabler(this, (WifiManager) getSystemService(WIFI_SERVICE),
138                 mWifiEnabled);
139 
140         mOpenNetworkNotificationsEnabled = (CheckBoxPreference) preferenceScreen
141                 .findPreference(KEY_OPEN_NETWORK_NOTIFICATIONS_ENABLED);
142         mOpenNetworkNotificationsEnabled.setChecked(Settings.Secure.getInt(getContentResolver(),
143             Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
144 
145         mAddOtherNetwork = preferenceScreen.findPreference(KEY_ADD_OTHER_NETWORK);
146 
147         registerForContextMenu(getListView());
148     }
149 
onCreatedWifi()150     private void onCreatedWifi() {
151     }
152 
153     @Override
onResume()154     protected void onResume() {
155         super.onResume();
156         mWifiLayer.onResume();
157         mWifiEnabler.resume();
158         // do what we should have after keystore is unlocked.
159         if (mResumeState != null) {
160             if (Keystore.getInstance().getState() == Keystore.UNLOCKED) {
161                 showAccessPointDialog(mResumeState, mResumeMode);
162             }
163             mResumeMode = -1;
164             mResumeState = null;
165         } else {
166             if (mResumeMode == AccessPointDialog.MODE_CONFIGURE) {
167                 if (Keystore.getInstance().getState() == Keystore.UNLOCKED) {
168                     ((AccessPointDialog) mDialog).enableEnterpriseFields();
169                 }
170             }
171         }
172     }
173 
174     @Override
onPause()175     protected void onPause() {
176         super.onPause();
177         mWifiLayer.onPause();
178         mWifiEnabler.pause();
179     }
180 
181     @Override
onDestroy()182     protected void onDestroy() {
183         super.onDestroy();
184 
185         if (mDialog != null) {
186             mDialog.dismiss();
187         }
188     }
189 
190     @Override
onCreateOptionsMenu(Menu menu)191     public boolean onCreateOptionsMenu(Menu menu) {
192         super.onCreateOptionsMenu(menu);
193 
194         menu.add(0, MENU_ID_SCAN, 0, R.string.scan_wifi)
195             .setIcon(R.drawable.ic_menu_scan_network);
196 
197         menu.add(0, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
198             .setIcon(android.R.drawable.ic_menu_manage);
199 
200         return true;
201     }
202 
203     @Override
onOptionsItemSelected(MenuItem item)204     public boolean onOptionsItemSelected(MenuItem item) {
205         super.onOptionsItemSelected(item);
206 
207         switch (item.getItemId()) {
208 
209             case MENU_ID_SCAN:
210                 mWifiLayer.attemptScan();
211                 return true;
212 
213             case MENU_ID_ADVANCED:
214                 Intent intent = new Intent(this, AdvancedSettings.class);
215                 startActivity(intent);
216                 return true;
217 
218             default:
219                 return false;
220         }
221     }
222 
223     @Override
onSaveInstanceState(Bundle outState)224     protected void onSaveInstanceState(Bundle outState) {
225         super.onSaveInstanceState(outState);
226 
227         if (mDialog != null) {
228             Bundle dialogBundle = mDialog.onSaveInstanceState();
229             outState.putBundle(INSTANCE_KEY_DIALOG_BUNDLE, dialogBundle);
230         }
231     }
232 
233     @Override
onRestoreInstanceState(Bundle state)234     protected void onRestoreInstanceState(Bundle state) {
235         super.onRestoreInstanceState(state);
236 
237         Bundle dialogBundle = state.getBundle(INSTANCE_KEY_DIALOG_BUNDLE);
238         if (dialogBundle != null) {
239             mDialog = new AccessPointDialog(this, mWifiLayer);
240             mDialog.onRestoreInstanceState(dialogBundle);
241             showDialog(mDialog);
242         }
243     }
244 
245     /**
246      * {@inheritDoc}
247      */
onDismiss(DialogInterface dialog)248     public void onDismiss(DialogInterface dialog) {
249         if (dialog == mDialog) {
250             mDialog = null;
251             mResumeMode = -1;
252         }
253     }
254 
255     @Override
onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)256     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
257         super.onCreateContextMenu(menu, v, menuInfo);
258 
259         AccessPointState state = getStateFromMenuInfo(menuInfo);
260         if (state == null) {
261             return;
262         }
263 
264         menu.setHeaderTitle(state.getHumanReadableSsid());
265 
266         if (state.isConnectable()) {
267             menu.add(0, CONTEXT_MENU_ID_CONNECT, 0, R.string.wifi_context_menu_connect);
268         }
269 
270         if (state.isForgetable()) {
271             menu.add(0, CONTEXT_MENU_ID_FORGET, 1, R.string.wifi_context_menu_forget);
272 
273             if (state.hasPassword()) {
274                 menu.add(0, CONTEXT_MENU_ID_CHANGE_PASSWORD, 2,
275                         R.string.wifi_context_menu_change_password);
276             }
277         }
278     }
279 
280     @Override
onContextItemSelected(MenuItem item)281     public boolean onContextItemSelected(MenuItem item) {
282 
283         AccessPointState state = getStateFromMenuInfo(item.getMenuInfo());
284         if (state == null) {
285             return false;
286         }
287 
288         switch (item.getItemId()) {
289 
290             case CONTEXT_MENU_ID_CONNECT:
291                 connectToNetwork(state);
292                 return true;
293 
294             case CONTEXT_MENU_ID_FORGET:
295                 mWifiLayer.forgetNetwork(state);
296                 return true;
297 
298             case CONTEXT_MENU_ID_CHANGE_PASSWORD:
299                 showAccessPointDialog(state, AccessPointDialog.MODE_CONFIGURE);
300                 return true;
301 
302             default:
303                 return false;
304         }
305     }
306 
307     /**
308      * Decides what needs to happen to connect to a particular access point. If
309      * it is secured and doesn't already have a password, it will bring up a
310      * password box. Otherwise it will just connect.
311      */
connectToNetwork(AccessPointState state)312     private void connectToNetwork(AccessPointState state) {
313         if (state.hasSecurity() && !state.hasPassword()) {
314             showAccessPointDialog(state, AccessPointDialog.MODE_INFO);
315         } else {
316             mWifiLayer.connectToNetwork(state);
317         }
318     }
319 
getStateFromMenuInfo(ContextMenuInfo menuInfo)320     private AccessPointState getStateFromMenuInfo(ContextMenuInfo menuInfo) {
321         if ((menuInfo == null) || !(menuInfo instanceof AdapterContextMenuInfo)) {
322             return null;
323         }
324 
325         AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
326         Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(
327                 adapterMenuInfo.position);
328         if (pref == null || !(pref instanceof AccessPointPreference)) {
329             return null;
330         }
331 
332         return ((AccessPointPreference) pref).getAccessPointState();
333     }
334 
335     //============================
336     // Preference callbacks
337     //============================
338 
339     @Override
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)340     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
341         super.onPreferenceTreeClick(preferenceScreen, preference);
342 
343         if (preference == mAddOtherNetwork) {
344             showAddOtherNetworkDialog();
345         } else if (preference == mOpenNetworkNotificationsEnabled) {
346             Settings.Secure.putInt(getContentResolver(),
347                 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
348                 mOpenNetworkNotificationsEnabled.isChecked() ? 1 : 0);
349         } else if (preference instanceof AccessPointPreference) {
350             AccessPointState state = ((AccessPointPreference) preference).getAccessPointState();
351             showAccessPointDialog(state, AccessPointDialog.MODE_INFO);
352         }
353 
354         return false;
355     }
356 
357     //============================
358     // Wifi-related
359     //============================
360 
getWifiLayer()361     public WifiLayer getWifiLayer() {
362         return mWifiLayer;
363     }
364 
showAddOtherNetworkDialog()365     private void showAddOtherNetworkDialog() {
366         AccessPointDialog dialog = new AccessPointDialog(this, mWifiLayer);
367         dialog.setState(new AccessPointState(this));
368         dialog.setMode(AccessPointDialog.MODE_CONFIGURE);
369         dialog.setTitle(R.string.wifi_add_other_network);
370         dialog.setAutoSecurityAllowed(false);
371         mResumeMode = AccessPointDialog.MODE_CONFIGURE;
372         showDialog(dialog);
373     }
374 
showAccessPointDialog(AccessPointState state, int mode)375     public void showAccessPointDialog(AccessPointState state, int mode) {
376         if (state.isEnterprise() &&
377                 Keystore.getInstance().getState() != Keystore.UNLOCKED) {
378             startActivity(new Intent(
379                     SecuritySettings.ACTION_UNLOCK_CREDENTIAL_STORAGE));
380             mResumeState = state;
381             mResumeMode = mode;
382             return;
383         }
384         AccessPointDialog dialog = new AccessPointDialog(this, mWifiLayer);
385         dialog.setMode(mode);
386         dialog.setState(state);
387         showDialog(dialog);
388     }
389 
showDialog(Dialog dialog)390     private void showDialog(Dialog dialog) {
391         // Have only one dialog open at a time
392         if (mDialog != null) {
393             mDialog.dismiss();
394         }
395 
396         mDialog = dialog;
397         dialog.setOnDismissListener(this);
398         if (dialog != null) {
399             dialog.show();
400         }
401     }
402 
403     //============================
404     // Wifi callbacks
405     //============================
406 
onError(int messageResId)407     public void onError(int messageResId) {
408         Toast.makeText(this, messageResId, Toast.LENGTH_LONG).show();
409     }
410 
onScanningStatusChanged(boolean started)411     public void onScanningStatusChanged(boolean started) {
412         mApCategory.setProgress(started);
413     }
414 
onAccessPointSetChanged(AccessPointState ap, boolean added)415     public void onAccessPointSetChanged(AccessPointState ap, boolean added) {
416 
417         AccessPointPreference pref = mAps.get(ap);
418 
419         if (WifiLayer.LOGV) {
420             Log.v(TAG, "onAccessPointSetChanged with " + ap + " and "
421                     + (added ? "added" : "removed") + ", found pref " + pref);
422         }
423 
424         if (added) {
425 
426             if (pref == null) {
427                 pref = new AccessPointPreference(this, ap);
428                 mAps.put(ap, pref);
429             } else {
430                 pref.setEnabled(true);
431             }
432 
433             mApCategory.addPreference(pref);
434 
435         } else {
436 
437             mAps.remove(ap);
438 
439             if (pref != null) {
440                 mApCategory.removePreference(pref);
441             }
442 
443         }
444     }
445 
onAccessPointsStateChanged(boolean enabled)446     public void onAccessPointsStateChanged(boolean enabled) {
447         if (enabled) {
448             mApCategory.setEnabled(true);
449         } else {
450             mApCategory.removeAll();
451             mAps.clear();
452         }
453 
454         mAddOtherNetwork.setEnabled(enabled);
455     }
456 
onRetryPassword(AccessPointState ap)457     public void onRetryPassword(AccessPointState ap) {
458 
459         if ((mDialog != null) && mDialog.isShowing()) {
460             // If we're already showing a dialog, ignore this request
461             return;
462         }
463 
464         showAccessPointDialog(ap, AccessPointDialog.MODE_RETRY_PASSWORD);
465     }
466 
467 }
468