1 /*
2  * Copyright (C) 2008 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;
18 
19 import android.app.Activity;
20 import android.app.Dialog;
21 import android.bluetooth.BluetoothAdapter;
22 import android.bluetooth.BluetoothPan;
23 import android.bluetooth.BluetoothProfile;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.pm.PackageManager;
30 import android.hardware.usb.UsbManager;
31 import android.net.ConnectivityManager;
32 import android.net.wifi.WifiConfiguration;
33 import android.net.wifi.WifiManager;
34 import android.os.Bundle;
35 import android.os.Environment;
36 import android.os.SystemProperties;
37 import android.os.UserHandle;
38 import android.os.UserManager;
39 import android.preference.Preference;
40 import android.preference.PreferenceScreen;
41 import android.preference.SwitchPreference;
42 import android.widget.TextView;
43 
44 import com.android.settings.wifi.WifiApDialog;
45 import com.android.settings.wifi.WifiApEnabler;
46 
47 import java.util.ArrayList;
48 import java.util.concurrent.atomic.AtomicReference;
49 
50 /*
51  * Displays preferences for Tethering.
52  */
53 public class TetherSettings extends SettingsPreferenceFragment
54         implements DialogInterface.OnClickListener, Preference.OnPreferenceChangeListener {
55     private static final String TAG = "TetherSettings";
56 
57     private static final String USB_TETHER_SETTINGS = "usb_tether_settings";
58     private static final String ENABLE_WIFI_AP = "enable_wifi_ap";
59     private static final String ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering";
60     private static final String TETHER_CHOICE = "TETHER_TYPE";
61 
62     private static final int DIALOG_AP_SETTINGS = 1;
63 
64     private SwitchPreference mUsbTether;
65 
66     private WifiApEnabler mWifiApEnabler;
67     private SwitchPreference mEnableWifiAp;
68 
69     private SwitchPreference mBluetoothTether;
70 
71     private BroadcastReceiver mTetherChangeReceiver;
72 
73     private String[] mUsbRegexs;
74 
75     private String[] mWifiRegexs;
76 
77     private String[] mBluetoothRegexs;
78     private AtomicReference<BluetoothPan> mBluetoothPan = new AtomicReference<BluetoothPan>();
79 
80     private static final String WIFI_AP_SSID_AND_SECURITY = "wifi_ap_ssid_and_security";
81     private static final int CONFIG_SUBTEXT = R.string.wifi_tether_configure_subtext;
82 
83     private String[] mSecurityType;
84     private Preference mCreateNetwork;
85 
86     private WifiApDialog mDialog;
87     private WifiManager mWifiManager;
88     private WifiConfiguration mWifiConfig = null;
89     private UserManager mUm;
90 
91     private boolean mUsbConnected;
92     private boolean mMassStorageActive;
93 
94     private boolean mBluetoothEnableForTether;
95 
96     public static final int INVALID             = -1;
97     public static final int WIFI_TETHERING      = 0;
98     public static final int USB_TETHERING       = 1;
99     public static final int BLUETOOTH_TETHERING = 2;
100 
101     /* One of INVALID, WIFI_TETHERING, USB_TETHERING or BLUETOOTH_TETHERING */
102     private int mTetherChoice = INVALID;
103 
104     /* Stores the package name and the class name of the provisioning app */
105     private String[] mProvisionApp;
106     private static final int PROVISION_REQUEST = 0;
107 
108     private boolean mUnavailable;
109 
110     @Override
onCreate(Bundle icicle)111     public void onCreate(Bundle icicle) {
112         super.onCreate(icicle);
113 
114         if(icicle != null) {
115             mTetherChoice = icicle.getInt(TETHER_CHOICE);
116         }
117         addPreferencesFromResource(R.xml.tether_prefs);
118 
119         mUm = (UserManager) getSystemService(Context.USER_SERVICE);
120 
121         if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
122             mUnavailable = true;
123             setPreferenceScreen(new PreferenceScreen(getActivity(), null));
124             return;
125         }
126 
127         final Activity activity = getActivity();
128         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
129         if (adapter != null) {
130             adapter.getProfileProxy(activity.getApplicationContext(), mProfileServiceListener,
131                     BluetoothProfile.PAN);
132         }
133 
134         mEnableWifiAp =
135                 (SwitchPreference) findPreference(ENABLE_WIFI_AP);
136         Preference wifiApSettings = findPreference(WIFI_AP_SSID_AND_SECURITY);
137         mUsbTether = (SwitchPreference) findPreference(USB_TETHER_SETTINGS);
138         mBluetoothTether = (SwitchPreference) findPreference(ENABLE_BLUETOOTH_TETHERING);
139 
140         ConnectivityManager cm =
141                 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
142 
143         mUsbRegexs = cm.getTetherableUsbRegexs();
144         mWifiRegexs = cm.getTetherableWifiRegexs();
145         mBluetoothRegexs = cm.getTetherableBluetoothRegexs();
146 
147         final boolean usbAvailable = mUsbRegexs.length != 0;
148         final boolean wifiAvailable = mWifiRegexs.length != 0;
149         final boolean bluetoothAvailable = mBluetoothRegexs.length != 0;
150 
151         if (!usbAvailable || Utils.isMonkeyRunning()) {
152             getPreferenceScreen().removePreference(mUsbTether);
153         }
154 
155         if (wifiAvailable && !Utils.isMonkeyRunning()) {
156             mWifiApEnabler = new WifiApEnabler(activity, mEnableWifiAp);
157             initWifiTethering();
158         } else {
159             getPreferenceScreen().removePreference(mEnableWifiAp);
160             getPreferenceScreen().removePreference(wifiApSettings);
161         }
162 
163         if (!bluetoothAvailable) {
164             getPreferenceScreen().removePreference(mBluetoothTether);
165         } else {
166             BluetoothPan pan = mBluetoothPan.get();
167             if (pan != null && pan.isTetheringOn()) {
168                 mBluetoothTether.setChecked(true);
169             } else {
170                 mBluetoothTether.setChecked(false);
171             }
172         }
173 
174         mProvisionApp = getResources().getStringArray(
175                 com.android.internal.R.array.config_mobile_hotspot_provision_app);
176     }
177 
178     @Override
onSaveInstanceState(Bundle savedInstanceState)179     public void onSaveInstanceState(Bundle savedInstanceState) {
180         savedInstanceState.putInt(TETHER_CHOICE, mTetherChoice);
181         super.onSaveInstanceState(savedInstanceState);
182     }
183 
initWifiTethering()184     private void initWifiTethering() {
185         final Activity activity = getActivity();
186         mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
187         mWifiConfig = mWifiManager.getWifiApConfiguration();
188         mSecurityType = getResources().getStringArray(R.array.wifi_ap_security);
189 
190         mCreateNetwork = findPreference(WIFI_AP_SSID_AND_SECURITY);
191 
192         if (mWifiConfig == null) {
193             final String s = activity.getString(
194                     com.android.internal.R.string.wifi_tether_configure_ssid_default);
195             mCreateNetwork.setSummary(String.format(activity.getString(CONFIG_SUBTEXT),
196                     s, mSecurityType[WifiApDialog.OPEN_INDEX]));
197         } else {
198             int index = WifiApDialog.getSecurityTypeIndex(mWifiConfig);
199             mCreateNetwork.setSummary(String.format(activity.getString(CONFIG_SUBTEXT),
200                     mWifiConfig.SSID,
201                     mSecurityType[index]));
202         }
203     }
204 
205     private BluetoothProfile.ServiceListener mProfileServiceListener =
206         new BluetoothProfile.ServiceListener() {
207         public void onServiceConnected(int profile, BluetoothProfile proxy) {
208             mBluetoothPan.set((BluetoothPan) proxy);
209         }
210         public void onServiceDisconnected(int profile) {
211             mBluetoothPan.set(null);
212         }
213     };
214 
215     @Override
onCreateDialog(int id)216     public Dialog onCreateDialog(int id) {
217         if (id == DIALOG_AP_SETTINGS) {
218             final Activity activity = getActivity();
219             mDialog = new WifiApDialog(activity, this, mWifiConfig);
220             return mDialog;
221         }
222 
223         return null;
224     }
225 
226     private class TetherChangeReceiver extends BroadcastReceiver {
227         @Override
onReceive(Context content, Intent intent)228         public void onReceive(Context content, Intent intent) {
229             String action = intent.getAction();
230             if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
231                 // TODO - this should understand the interface types
232                 ArrayList<String> available = intent.getStringArrayListExtra(
233                         ConnectivityManager.EXTRA_AVAILABLE_TETHER);
234                 ArrayList<String> active = intent.getStringArrayListExtra(
235                         ConnectivityManager.EXTRA_ACTIVE_TETHER);
236                 ArrayList<String> errored = intent.getStringArrayListExtra(
237                         ConnectivityManager.EXTRA_ERRORED_TETHER);
238                 updateState(available.toArray(new String[available.size()]),
239                         active.toArray(new String[active.size()]),
240                         errored.toArray(new String[errored.size()]));
241             } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
242                 mMassStorageActive = true;
243                 updateState();
244             } else if (action.equals(Intent.ACTION_MEDIA_UNSHARED)) {
245                 mMassStorageActive = false;
246                 updateState();
247             } else if (action.equals(UsbManager.ACTION_USB_STATE)) {
248                 mUsbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
249                 updateState();
250             } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
251                 if (mBluetoothEnableForTether) {
252                     switch (intent
253                             .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) {
254                         case BluetoothAdapter.STATE_ON:
255                             BluetoothPan bluetoothPan = mBluetoothPan.get();
256                             if (bluetoothPan != null) {
257                                 bluetoothPan.setBluetoothTethering(true);
258                                 mBluetoothEnableForTether = false;
259                             }
260                             break;
261 
262                         case BluetoothAdapter.STATE_OFF:
263                         case BluetoothAdapter.ERROR:
264                             mBluetoothEnableForTether = false;
265                             break;
266 
267                         default:
268                             // ignore transition states
269                     }
270                 }
271                 updateState();
272             }
273         }
274     }
275 
276     @Override
onStart()277     public void onStart() {
278         super.onStart();
279 
280         if (mUnavailable) {
281             TextView emptyView = (TextView) getView().findViewById(android.R.id.empty);
282             getListView().setEmptyView(emptyView);
283             if (emptyView != null) {
284                 emptyView.setText(R.string.tethering_settings_not_available);
285             }
286             return;
287         }
288 
289         final Activity activity = getActivity();
290 
291         mMassStorageActive = Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState());
292         mTetherChangeReceiver = new TetherChangeReceiver();
293         IntentFilter filter = new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
294         Intent intent = activity.registerReceiver(mTetherChangeReceiver, filter);
295 
296         filter = new IntentFilter();
297         filter.addAction(UsbManager.ACTION_USB_STATE);
298         activity.registerReceiver(mTetherChangeReceiver, filter);
299 
300         filter = new IntentFilter();
301         filter.addAction(Intent.ACTION_MEDIA_SHARED);
302         filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
303         filter.addDataScheme("file");
304         activity.registerReceiver(mTetherChangeReceiver, filter);
305 
306         filter = new IntentFilter();
307         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
308         activity.registerReceiver(mTetherChangeReceiver, filter);
309 
310         if (intent != null) mTetherChangeReceiver.onReceive(activity, intent);
311         if (mWifiApEnabler != null) {
312             mEnableWifiAp.setOnPreferenceChangeListener(this);
313             mWifiApEnabler.resume();
314         }
315 
316         updateState();
317     }
318 
319     @Override
onStop()320     public void onStop() {
321         super.onStop();
322 
323         if (mUnavailable) {
324             return;
325         }
326         getActivity().unregisterReceiver(mTetherChangeReceiver);
327         mTetherChangeReceiver = null;
328         if (mWifiApEnabler != null) {
329             mEnableWifiAp.setOnPreferenceChangeListener(null);
330             mWifiApEnabler.pause();
331         }
332     }
333 
updateState()334     private void updateState() {
335         ConnectivityManager cm =
336                 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
337 
338         String[] available = cm.getTetherableIfaces();
339         String[] tethered = cm.getTetheredIfaces();
340         String[] errored = cm.getTetheringErroredIfaces();
341         updateState(available, tethered, errored);
342     }
343 
updateState(String[] available, String[] tethered, String[] errored)344     private void updateState(String[] available, String[] tethered,
345             String[] errored) {
346         updateUsbState(available, tethered, errored);
347         updateBluetoothState(available, tethered, errored);
348     }
349 
350 
updateUsbState(String[] available, String[] tethered, String[] errored)351     private void updateUsbState(String[] available, String[] tethered,
352             String[] errored) {
353         ConnectivityManager cm =
354                 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
355         boolean usbAvailable = mUsbConnected && !mMassStorageActive;
356         int usbError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
357         for (String s : available) {
358             for (String regex : mUsbRegexs) {
359                 if (s.matches(regex)) {
360                     if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
361                         usbError = cm.getLastTetherError(s);
362                     }
363                 }
364             }
365         }
366         boolean usbTethered = false;
367         for (String s : tethered) {
368             for (String regex : mUsbRegexs) {
369                 if (s.matches(regex)) usbTethered = true;
370             }
371         }
372         boolean usbErrored = false;
373         for (String s: errored) {
374             for (String regex : mUsbRegexs) {
375                 if (s.matches(regex)) usbErrored = true;
376             }
377         }
378 
379         if (usbTethered) {
380             mUsbTether.setSummary(R.string.usb_tethering_active_subtext);
381             mUsbTether.setEnabled(true);
382             mUsbTether.setChecked(true);
383         } else if (usbAvailable) {
384             if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
385                 mUsbTether.setSummary(R.string.usb_tethering_available_subtext);
386             } else {
387                 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
388             }
389             mUsbTether.setEnabled(true);
390             mUsbTether.setChecked(false);
391         } else if (usbErrored) {
392             mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
393             mUsbTether.setEnabled(false);
394             mUsbTether.setChecked(false);
395         } else if (mMassStorageActive) {
396             mUsbTether.setSummary(R.string.usb_tethering_storage_active_subtext);
397             mUsbTether.setEnabled(false);
398             mUsbTether.setChecked(false);
399         } else {
400             mUsbTether.setSummary(R.string.usb_tethering_unavailable_subtext);
401             mUsbTether.setEnabled(false);
402             mUsbTether.setChecked(false);
403         }
404     }
405 
updateBluetoothState(String[] available, String[] tethered, String[] errored)406     private void updateBluetoothState(String[] available, String[] tethered,
407             String[] errored) {
408         boolean bluetoothErrored = false;
409         for (String s: errored) {
410             for (String regex : mBluetoothRegexs) {
411                 if (s.matches(regex)) bluetoothErrored = true;
412             }
413         }
414 
415         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
416         if (adapter == null)
417             return;
418         int btState = adapter.getState();
419         if (btState == BluetoothAdapter.STATE_TURNING_OFF) {
420             mBluetoothTether.setEnabled(false);
421             mBluetoothTether.setSummary(R.string.bluetooth_turning_off);
422         } else if (btState == BluetoothAdapter.STATE_TURNING_ON) {
423             mBluetoothTether.setEnabled(false);
424             mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
425         } else {
426             BluetoothPan bluetoothPan = mBluetoothPan.get();
427             if (btState == BluetoothAdapter.STATE_ON && bluetoothPan != null &&
428                     bluetoothPan.isTetheringOn()) {
429                 mBluetoothTether.setChecked(true);
430                 mBluetoothTether.setEnabled(true);
431                 int bluetoothTethered = bluetoothPan.getConnectedDevices().size();
432                 if (bluetoothTethered > 1) {
433                     String summary = getString(
434                             R.string.bluetooth_tethering_devices_connected_subtext,
435                             bluetoothTethered);
436                     mBluetoothTether.setSummary(summary);
437                 } else if (bluetoothTethered == 1) {
438                     mBluetoothTether.setSummary(
439                             R.string.bluetooth_tethering_device_connected_subtext);
440                 } else if (bluetoothErrored) {
441                     mBluetoothTether.setSummary(R.string.bluetooth_tethering_errored_subtext);
442                 } else {
443                     mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
444                 }
445             } else {
446                 mBluetoothTether.setEnabled(true);
447                 mBluetoothTether.setChecked(false);
448                 mBluetoothTether.setSummary(R.string.bluetooth_tethering_off_subtext);
449             }
450         }
451     }
452 
onPreferenceChange(Preference preference, Object value)453     public boolean onPreferenceChange(Preference preference, Object value) {
454         boolean enable = (Boolean) value;
455 
456         if (enable) {
457             startProvisioningIfNecessary(WIFI_TETHERING);
458         } else {
459             if (isProvisioningNeeded(mProvisionApp)) {
460                 TetherService.cancelRecheckAlarmIfNecessary(getActivity(), WIFI_TETHERING);
461             }
462             mWifiApEnabler.setSoftapEnabled(false);
463         }
464         return false;
465     }
466 
isProvisioningNeededButUnavailable(Context context)467     public static boolean isProvisioningNeededButUnavailable(Context context) {
468         String[] provisionApp = context.getResources().getStringArray(
469                 com.android.internal.R.array.config_mobile_hotspot_provision_app);
470         return (isProvisioningNeeded(provisionApp)
471                 && !isIntentAvailable(context, provisionApp));
472     }
473 
isIntentAvailable(Context context, String[] provisionApp)474     private static boolean isIntentAvailable(Context context, String[] provisionApp) {
475         if (provisionApp.length <  2) {
476             throw new IllegalArgumentException("provisionApp length should at least be 2");
477         }
478         final PackageManager packageManager = context.getPackageManager();
479         Intent intent = new Intent(Intent.ACTION_MAIN);
480         intent.setClassName(provisionApp[0], provisionApp[1]);
481 
482         return (packageManager.queryIntentActivities(intent,
483                 PackageManager.MATCH_DEFAULT_ONLY).size() > 0);
484     }
485 
486 
isProvisioningNeeded(String[] provisionApp)487     private static boolean isProvisioningNeeded(String[] provisionApp) {
488         if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)
489                 || provisionApp == null) {
490             return false;
491         }
492         return (provisionApp.length == 2);
493     }
494 
startProvisioningIfNecessary(int choice)495     private void startProvisioningIfNecessary(int choice) {
496         mTetherChoice = choice;
497         if (isProvisioningNeeded(mProvisionApp)) {
498             Intent intent = new Intent(Intent.ACTION_MAIN);
499             intent.setClassName(mProvisionApp[0], mProvisionApp[1]);
500             intent.putExtra(TETHER_CHOICE, mTetherChoice);
501             startActivityForResult(intent, PROVISION_REQUEST);
502         } else {
503             startTethering();
504         }
505     }
506 
onActivityResult(int requestCode, int resultCode, Intent intent)507     public void onActivityResult(int requestCode, int resultCode, Intent intent) {
508         super.onActivityResult(requestCode, resultCode, intent);
509         if (requestCode == PROVISION_REQUEST) {
510             if (resultCode == Activity.RESULT_OK) {
511                 TetherService.scheduleRecheckAlarm(getActivity(), mTetherChoice);
512                 startTethering();
513             } else {
514                 //BT and USB need switch turned off on failure
515                 //Wifi tethering is never turned on until afterwards
516                 switch (mTetherChoice) {
517                     case BLUETOOTH_TETHERING:
518                         mBluetoothTether.setChecked(false);
519                         break;
520                     case USB_TETHERING:
521                         mUsbTether.setChecked(false);
522                         break;
523                 }
524                 mTetherChoice = INVALID;
525             }
526         }
527     }
528 
startTethering()529     private void startTethering() {
530         switch (mTetherChoice) {
531             case WIFI_TETHERING:
532                 mWifiApEnabler.setSoftapEnabled(true);
533                 break;
534             case BLUETOOTH_TETHERING:
535                 // turn on Bluetooth first
536                 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
537                 if (adapter.getState() == BluetoothAdapter.STATE_OFF) {
538                     mBluetoothEnableForTether = true;
539                     adapter.enable();
540                     mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
541                     mBluetoothTether.setEnabled(false);
542                 } else {
543                     BluetoothPan bluetoothPan = mBluetoothPan.get();
544                     if (bluetoothPan != null) bluetoothPan.setBluetoothTethering(true);
545                     mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
546                 }
547                 break;
548             case USB_TETHERING:
549                 setUsbTethering(true);
550                 break;
551             default:
552                 //should not happen
553                 break;
554         }
555     }
556 
setUsbTethering(boolean enabled)557     private void setUsbTethering(boolean enabled) {
558         ConnectivityManager cm =
559             (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
560         mUsbTether.setChecked(false);
561         if (cm.setUsbTethering(enabled) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
562             mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
563             return;
564         }
565         mUsbTether.setSummary("");
566     }
567 
568     @Override
onPreferenceTreeClick(PreferenceScreen screen, Preference preference)569     public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
570         ConnectivityManager cm =
571                 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
572 
573         if (preference == mUsbTether) {
574             boolean newState = mUsbTether.isChecked();
575 
576             if (newState) {
577                 startProvisioningIfNecessary(USB_TETHERING);
578             } else {
579                 if (isProvisioningNeeded(mProvisionApp)) {
580                     TetherService.cancelRecheckAlarmIfNecessary(getActivity(), USB_TETHERING);
581                 }
582                 setUsbTethering(newState);
583             }
584         } else if (preference == mBluetoothTether) {
585             boolean bluetoothTetherState = mBluetoothTether.isChecked();
586 
587             if (bluetoothTetherState) {
588                 startProvisioningIfNecessary(BLUETOOTH_TETHERING);
589             } else {
590                 if (isProvisioningNeeded(mProvisionApp)) {
591                     TetherService.cancelRecheckAlarmIfNecessary(getActivity(), BLUETOOTH_TETHERING);
592                 }
593                 boolean errored = false;
594 
595                 String [] tethered = cm.getTetheredIfaces();
596                 String bluetoothIface = findIface(tethered, mBluetoothRegexs);
597                 if (bluetoothIface != null &&
598                         cm.untether(bluetoothIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
599                     errored = true;
600                 }
601 
602                 BluetoothPan bluetoothPan = mBluetoothPan.get();
603                 if (bluetoothPan != null) bluetoothPan.setBluetoothTethering(false);
604                 if (errored) {
605                     mBluetoothTether.setSummary(R.string.bluetooth_tethering_errored_subtext);
606                 } else {
607                     mBluetoothTether.setSummary(R.string.bluetooth_tethering_off_subtext);
608                 }
609             }
610         } else if (preference == mCreateNetwork) {
611             showDialog(DIALOG_AP_SETTINGS);
612         }
613 
614         return super.onPreferenceTreeClick(screen, preference);
615     }
616 
findIface(String[] ifaces, String[] regexes)617     private static String findIface(String[] ifaces, String[] regexes) {
618         for (String iface : ifaces) {
619             for (String regex : regexes) {
620                 if (iface.matches(regex)) {
621                     return iface;
622                 }
623             }
624         }
625         return null;
626     }
627 
onClick(DialogInterface dialogInterface, int button)628     public void onClick(DialogInterface dialogInterface, int button) {
629         if (button == DialogInterface.BUTTON_POSITIVE) {
630             mWifiConfig = mDialog.getConfig();
631             if (mWifiConfig != null) {
632                 /**
633                  * if soft AP is stopped, bring up
634                  * else restart with new config
635                  * TODO: update config on a running access point when framework support is added
636                  */
637                 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
638                     mWifiManager.setWifiApEnabled(null, false);
639                     mWifiManager.setWifiApEnabled(mWifiConfig, true);
640                 } else {
641                     mWifiManager.setWifiApConfiguration(mWifiConfig);
642                 }
643                 int index = WifiApDialog.getSecurityTypeIndex(mWifiConfig);
644                 mCreateNetwork.setSummary(String.format(getActivity().getString(CONFIG_SUBTEXT),
645                         mWifiConfig.SSID,
646                         mSecurityType[index]));
647             }
648         }
649     }
650 
651     @Override
getHelpResource()652     public int getHelpResource() {
653         return R.string.help_url_tether;
654     }
655 
656     /**
657      * Checks whether this screen will have anything to show on this device. This is called by
658      * the shortcut picker for Settings shortcuts (home screen widget).
659      * @param context a context object for getting a system service.
660      * @return whether Tether & portable hotspot should be shown in the shortcuts picker.
661      */
showInShortcuts(Context context)662     public static boolean showInShortcuts(Context context) {
663         final ConnectivityManager cm =
664                 (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
665         final boolean isSecondaryUser = UserHandle.myUserId() != UserHandle.USER_OWNER;
666         return !isSecondaryUser && cm.isTetheringSupported();
667     }
668 }
669