2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
19 import static com.android.settingslib.TetherUtil.TETHERING_INVALID;
20 import static com.android.settingslib.TetherUtil.TETHERING_WIFI;
21 import static com.android.settingslib.TetherUtil.TETHERING_USB;
22 import static com.android.settingslib.TetherUtil.TETHERING_BLUETOOTH;
24 import android.app.Activity;
25 import android.app.Dialog;
26 import android.bluetooth.BluetoothAdapter;
27 import android.bluetooth.BluetoothPan;
28 import android.bluetooth.BluetoothProfile;
29 import android.content.BroadcastReceiver;
30 import android.content.Context;
31 import android.content.DialogInterface;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.pm.PackageManager;
35 import android.hardware.usb.UsbManager;
36 import android.net.ConnectivityManager;
37 import android.net.wifi.WifiConfiguration;
38 import android.net.wifi.WifiManager;
39 import android.os.Bundle;
40 import android.os.Environment;
41 import android.os.UserHandle;
42 import android.os.UserManager;
43 import android.preference.ListPreference;
44 import android.preference.Preference;
45 import android.preference.PreferenceScreen;
46 import android.preference.SwitchPreference;
47 import android.widget.TextView;
49 import com.android.internal.logging.MetricsLogger;
50 import com.android.settings.wifi.WifiApDialog;
51 import com.android.settings.wifi.WifiApEnabler;
52 import com.android.settingslib.TetherUtil;
54 import java.util.ArrayList;
55 import java.util.concurrent.atomic.AtomicReference;
58 * Displays preferences for Tethering.
60 public class TetherSettings extends SettingsPreferenceFragment
61 implements DialogInterface.OnClickListener, Preference.OnPreferenceChangeListener {
62 private static final String TAG = "TetherSettings";
64 private static final String USB_TETHER_SETTINGS = "usb_tether_settings";
65 private static final String ENABLE_WIFI_AP = "enable_wifi_ap";
66 private static final String ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering";
67 private static final String TETHER_CHOICE = "TETHER_TYPE";
68 private static final String HOTSPOT_TIMEOUT = "hotstpot_inactivity_timeout";
70 private static final int DIALOG_AP_SETTINGS = 1;
72 private SwitchPreference mUsbTether;
74 private WifiApEnabler mWifiApEnabler;
75 private SwitchPreference mEnableWifiAp;
77 private SwitchPreference mBluetoothTether;
79 private ListPreference mHotspotInactivityTimeout;
81 private BroadcastReceiver mTetherChangeReceiver;
83 private String[] mUsbRegexs;
85 private String[] mWifiRegexs;
87 private String[] mBluetoothRegexs;
88 private AtomicReference<BluetoothPan> mBluetoothPan = new AtomicReference<BluetoothPan>();
90 private static final String WIFI_AP_SSID_AND_SECURITY = "wifi_ap_ssid_and_security";
91 private static final int CONFIG_SUBTEXT = R.string.wifi_tether_configure_subtext;
93 private String[] mSecurityType;
94 private Preference mCreateNetwork;
96 private WifiApDialog mDialog;
97 private WifiManager mWifiManager;
98 private WifiConfiguration mWifiConfig = null;
99 private UserManager mUm;
101 private boolean mUsbConnected;
102 private boolean mMassStorageActive;
104 private boolean mBluetoothEnableForTether;
106 /* One of INVALID, WIFI_TETHERING, USB_TETHERING or BLUETOOTH_TETHERING */
107 private int mTetherChoice = TETHERING_INVALID;
109 /* Stores the package name and the class name of the provisioning app */
110 private String[] mProvisionApp;
111 private static final int PROVISION_REQUEST = 0;
113 private boolean mUnavailable;
116 protected int getMetricsCategory() {
117 return MetricsLogger.TETHER;
121 public void onCreate(Bundle icicle) {
122 super.onCreate(icicle);
125 mTetherChoice = icicle.getInt(TETHER_CHOICE);
127 addPreferencesFromResource(R.xml.tether_prefs);
129 mUm = (UserManager) getSystemService(Context.USER_SERVICE);
131 if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)
132 || UserHandle.myUserId() != UserHandle.USER_OWNER) {
134 setPreferenceScreen(new PreferenceScreen(getActivity(), null));
138 final Activity activity = getActivity();
139 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
140 if (adapter != null) {
141 adapter.getProfileProxy(activity.getApplicationContext(), mProfileServiceListener,
142 BluetoothProfile.PAN);
146 (SwitchPreference) findPreference(ENABLE_WIFI_AP);
147 Preference wifiApSettings = findPreference(WIFI_AP_SSID_AND_SECURITY);
148 mUsbTether = (SwitchPreference) findPreference(USB_TETHER_SETTINGS);
149 mBluetoothTether = (SwitchPreference) findPreference(ENABLE_BLUETOOTH_TETHERING);
150 mHotspotInactivityTimeout = (ListPreference) findPreference(HOTSPOT_TIMEOUT);
152 ConnectivityManager cm =
153 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
155 mUsbRegexs = cm.getTetherableUsbRegexs();
156 mWifiRegexs = cm.getTetherableWifiRegexs();
157 mBluetoothRegexs = cm.getTetherableBluetoothRegexs();
159 final boolean usbAvailable = mUsbRegexs.length != 0;
160 final boolean wifiAvailable = mWifiRegexs.length != 0;
161 final boolean bluetoothAvailable = mBluetoothRegexs.length != 0;
163 if (!usbAvailable || Utils.isMonkeyRunning()) {
164 getPreferenceScreen().removePreference(mUsbTether);
167 if (wifiAvailable && !Utils.isMonkeyRunning()) {
168 mWifiApEnabler = new WifiApEnabler(activity, mEnableWifiAp);
171 getPreferenceScreen().removePreference(mEnableWifiAp);
172 getPreferenceScreen().removePreference(wifiApSettings);
175 if (!bluetoothAvailable) {
176 getPreferenceScreen().removePreference(mBluetoothTether);
178 BluetoothPan pan = mBluetoothPan.get();
179 if (pan != null && pan.isTetheringOn()) {
180 mBluetoothTether.setChecked(true);
182 mBluetoothTether.setChecked(false);
186 mProvisionApp = getResources().getStringArray(
187 com.android.internal.R.array.config_mobile_hotspot_provision_app);
188 mHotspotInactivityTimeout.setOnPreferenceChangeListener(this);
192 public void onSaveInstanceState(Bundle savedInstanceState) {
193 savedInstanceState.putInt(TETHER_CHOICE, mTetherChoice);
194 super.onSaveInstanceState(savedInstanceState);
197 private void initWifiTethering() {
198 final Activity activity = getActivity();
199 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
200 mWifiConfig = mWifiManager.getWifiApConfiguration();
201 mSecurityType = getResources().getStringArray(R.array.wifi_ap_security);
203 mCreateNetwork = findPreference(WIFI_AP_SSID_AND_SECURITY);
205 if (mWifiConfig == null) {
206 final String s = activity.getString(
207 com.android.internal.R.string.wifi_tether_configure_ssid_default);
208 mCreateNetwork.setSummary(String.format(activity.getString(CONFIG_SUBTEXT),
209 s, mSecurityType[WifiApDialog.OPEN_INDEX]));
211 int index = WifiApDialog.getSecurityTypeIndex(mWifiConfig);
212 mCreateNetwork.setSummary(String.format(activity.getString(CONFIG_SUBTEXT),
214 mSecurityType[index]));
216 updateHotspotTimeoutSummary(mWifiConfig);
219 private void updateHotspotTimeoutSummary(WifiConfiguration wifiConfig) {
220 if (wifiConfig == null) {
221 mHotspotInactivityTimeout.setValue("0");
222 mHotspotInactivityTimeout.setSummary(
223 getString(R.string.hotstpot_inactivity_timeout_never_summary_text));
225 mHotspotInactivityTimeout.setValue(Long.toString(wifiConfig.wifiApInactivityTimeout));
226 if (wifiConfig.wifiApInactivityTimeout > 0) {
227 mHotspotInactivityTimeout.setSummary(String.format(
228 getString(R.string.hotstpot_inactivity_timeout_summary_text,
229 mHotspotInactivityTimeout.getEntry())));
231 mHotspotInactivityTimeout.setSummary(
232 getString(R.string.hotstpot_inactivity_timeout_never_summary_text));
237 private BluetoothProfile.ServiceListener mProfileServiceListener =
238 new BluetoothProfile.ServiceListener() {
239 public void onServiceConnected(int profile, BluetoothProfile proxy) {
240 mBluetoothPan.set((BluetoothPan) proxy);
242 public void onServiceDisconnected(int profile) {
243 mBluetoothPan.set(null);
248 public Dialog onCreateDialog(int id) {
249 if (id == DIALOG_AP_SETTINGS) {
250 final Activity activity = getActivity();
251 mDialog = new WifiApDialog(activity, this, mWifiConfig);
258 private class TetherChangeReceiver extends BroadcastReceiver {
260 public void onReceive(Context content, Intent intent) {
261 String action = intent.getAction();
262 if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
263 // TODO - this should understand the interface types
264 ArrayList<String> available = intent.getStringArrayListExtra(
265 ConnectivityManager.EXTRA_AVAILABLE_TETHER);
266 ArrayList<String> active = intent.getStringArrayListExtra(
267 ConnectivityManager.EXTRA_ACTIVE_TETHER);
268 ArrayList<String> errored = intent.getStringArrayListExtra(
269 ConnectivityManager.EXTRA_ERRORED_TETHER);
270 updateState(available.toArray(new String[available.size()]),
271 active.toArray(new String[active.size()]),
272 errored.toArray(new String[errored.size()]));
273 } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
274 mMassStorageActive = true;
276 } else if (action.equals(Intent.ACTION_MEDIA_UNSHARED)) {
277 mMassStorageActive = false;
279 } else if (action.equals(UsbManager.ACTION_USB_STATE)) {
280 mUsbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
282 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
283 if (mBluetoothEnableForTether) {
285 .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) {
286 case BluetoothAdapter.STATE_ON:
287 BluetoothPan bluetoothPan = mBluetoothPan.get();
288 if (bluetoothPan != null) {
289 bluetoothPan.setBluetoothTethering(true);
290 mBluetoothEnableForTether = false;
294 case BluetoothAdapter.STATE_OFF:
295 case BluetoothAdapter.ERROR:
296 mBluetoothEnableForTether = false;
300 // ignore transition states
309 public void onStart() {
313 TextView emptyView = (TextView) getView().findViewById(android.R.id.empty);
314 getListView().setEmptyView(emptyView);
315 if (emptyView != null) {
316 emptyView.setText(R.string.tethering_settings_not_available);
321 final Activity activity = getActivity();
323 mMassStorageActive = Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState());
324 mTetherChangeReceiver = new TetherChangeReceiver();
325 IntentFilter filter = new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
326 Intent intent = activity.registerReceiver(mTetherChangeReceiver, filter);
328 filter = new IntentFilter();
329 filter.addAction(UsbManager.ACTION_USB_STATE);
330 activity.registerReceiver(mTetherChangeReceiver, filter);
332 filter = new IntentFilter();
333 filter.addAction(Intent.ACTION_MEDIA_SHARED);
334 filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
335 filter.addDataScheme("file");
336 activity.registerReceiver(mTetherChangeReceiver, filter);
338 filter = new IntentFilter();
339 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
340 activity.registerReceiver(mTetherChangeReceiver, filter);
342 if (intent != null) mTetherChangeReceiver.onReceive(activity, intent);
343 if (mWifiApEnabler != null) {
344 mEnableWifiAp.setOnPreferenceChangeListener(this);
345 mWifiApEnabler.resume();
352 public void onStop() {
358 getActivity().unregisterReceiver(mTetherChangeReceiver);
359 mTetherChangeReceiver = null;
360 if (mWifiApEnabler != null) {
361 mEnableWifiAp.setOnPreferenceChangeListener(null);
362 mWifiApEnabler.pause();
366 private void updateState() {
367 ConnectivityManager cm =
368 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
370 String[] available = cm.getTetherableIfaces();
371 String[] tethered = cm.getTetheredIfaces();
372 String[] errored = cm.getTetheringErroredIfaces();
373 updateState(available, tethered, errored);
376 private void updateState(String[] available, String[] tethered,
378 updateUsbState(available, tethered, errored);
379 updateBluetoothState(available, tethered, errored);
383 private void updateUsbState(String[] available, String[] tethered,
385 ConnectivityManager cm =
386 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
387 boolean usbAvailable = mUsbConnected && !mMassStorageActive;
388 int usbError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
389 for (String s : available) {
390 for (String regex : mUsbRegexs) {
391 if (s.matches(regex)) {
392 if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
393 usbError = cm.getLastTetherError(s);
398 boolean usbTethered = false;
399 for (String s : tethered) {
400 for (String regex : mUsbRegexs) {
401 if (s.matches(regex)) usbTethered = true;
404 boolean usbErrored = false;
405 for (String s: errored) {
406 for (String regex : mUsbRegexs) {
407 if (s.matches(regex)) usbErrored = true;
412 mUsbTether.setSummary(R.string.usb_tethering_active_subtext);
413 mUsbTether.setEnabled(true);
414 mUsbTether.setChecked(true);
415 } else if (usbAvailable) {
416 if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
417 mUsbTether.setSummary(R.string.usb_tethering_available_subtext);
419 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
421 mUsbTether.setEnabled(true);
422 mUsbTether.setChecked(false);
423 } else if (usbErrored) {
424 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
425 mUsbTether.setEnabled(false);
426 mUsbTether.setChecked(false);
427 } else if (mMassStorageActive) {
428 mUsbTether.setSummary(R.string.usb_tethering_storage_active_subtext);
429 mUsbTether.setEnabled(false);
430 mUsbTether.setChecked(false);
432 mUsbTether.setSummary(R.string.usb_tethering_unavailable_subtext);
433 mUsbTether.setEnabled(false);
434 mUsbTether.setChecked(false);
438 private void updateBluetoothState(String[] available, String[] tethered,
440 boolean bluetoothErrored = false;
441 for (String s: errored) {
442 for (String regex : mBluetoothRegexs) {
443 if (s.matches(regex)) bluetoothErrored = true;
447 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
450 int btState = adapter.getState();
451 if (btState == BluetoothAdapter.STATE_TURNING_OFF) {
452 mBluetoothTether.setEnabled(false);
453 mBluetoothTether.setSummary(R.string.bluetooth_turning_off);
454 } else if (btState == BluetoothAdapter.STATE_TURNING_ON) {
455 mBluetoothTether.setEnabled(false);
456 mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
458 BluetoothPan bluetoothPan = mBluetoothPan.get();
459 if (btState == BluetoothAdapter.STATE_ON && bluetoothPan != null &&
460 bluetoothPan.isTetheringOn()) {
461 mBluetoothTether.setChecked(true);
462 mBluetoothTether.setEnabled(true);
463 int bluetoothTethered = bluetoothPan.getConnectedDevices().size();
464 if (bluetoothTethered > 1) {
465 String summary = getString(
466 R.string.bluetooth_tethering_devices_connected_subtext,
468 mBluetoothTether.setSummary(summary);
469 } else if (bluetoothTethered == 1) {
470 mBluetoothTether.setSummary(
471 R.string.bluetooth_tethering_device_connected_subtext);
472 } else if (bluetoothErrored) {
473 mBluetoothTether.setSummary(R.string.bluetooth_tethering_errored_subtext);
475 mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
478 mBluetoothTether.setEnabled(true);
479 mBluetoothTether.setChecked(false);
480 mBluetoothTether.setSummary(R.string.bluetooth_tethering_off_subtext);
485 public boolean onPreferenceChange(Preference preference, Object value) {
486 if (preference == mEnableWifiAp) {
487 boolean enable = (Boolean) value;
490 startProvisioningIfNecessary(TETHERING_WIFI);
492 if (TetherUtil.isProvisioningNeeded(getActivity())) {
493 TetherService.cancelRecheckAlarmIfNecessary(getActivity(), TETHERING_WIFI);
495 mWifiApEnabler.setSoftapEnabled(false);
498 } else if (preference == mHotspotInactivityTimeout) {
499 if (mWifiConfig != null) {
500 mWifiConfig.wifiApInactivityTimeout = Long.parseLong((String) value);
501 updateHotspotTimeoutSummary(mWifiConfig);
502 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
503 mWifiManager.setWifiApEnabled(null, false);
504 mWifiManager.setWifiApEnabled(mWifiConfig, true);
506 mWifiManager.setWifiApConfiguration(mWifiConfig);
514 public static boolean isProvisioningNeededButUnavailable(Context context) {
515 return (TetherUtil.isProvisioningNeeded(context)
516 && !isIntentAvailable(context));
519 private static boolean isIntentAvailable(Context context) {
520 String[] provisionApp = context.getResources().getStringArray(
521 com.android.internal.R.array.config_mobile_hotspot_provision_app);
522 final PackageManager packageManager = context.getPackageManager();
523 Intent intent = new Intent(Intent.ACTION_MAIN);
524 intent.setClassName(provisionApp[0], provisionApp[1]);
526 return (packageManager.queryIntentActivities(intent,
527 PackageManager.MATCH_DEFAULT_ONLY).size() > 0);
530 private void startProvisioningIfNecessary(int choice) {
531 mTetherChoice = choice;
532 if (TetherUtil.isProvisioningNeeded(getActivity())) {
533 Intent intent = new Intent(Intent.ACTION_MAIN);
534 intent.setClassName(mProvisionApp[0], mProvisionApp[1]);
535 intent.putExtra(TETHER_CHOICE, mTetherChoice);
536 startActivityForResult(intent, PROVISION_REQUEST);
542 public void onActivityResult(int requestCode, int resultCode, Intent intent) {
543 super.onActivityResult(requestCode, resultCode, intent);
544 if (requestCode == PROVISION_REQUEST) {
545 if (resultCode == Activity.RESULT_OK) {
546 TetherService.scheduleRecheckAlarm(getActivity(), mTetherChoice);
549 //BT and USB need switch turned off on failure
550 //Wifi tethering is never turned on until afterwards
551 switch (mTetherChoice) {
552 case TETHERING_BLUETOOTH:
553 mBluetoothTether.setChecked(false);
556 mUsbTether.setChecked(false);
559 mTetherChoice = TETHERING_INVALID;
564 private void startTethering() {
565 switch (mTetherChoice) {
567 mWifiApEnabler.setSoftapEnabled(true);
569 case TETHERING_BLUETOOTH:
570 // turn on Bluetooth first
571 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
572 if (adapter.getState() == BluetoothAdapter.STATE_OFF) {
573 mBluetoothEnableForTether = true;
575 mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
576 mBluetoothTether.setEnabled(false);
578 BluetoothPan bluetoothPan = mBluetoothPan.get();
579 if (bluetoothPan != null) bluetoothPan.setBluetoothTethering(true);
580 mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
584 setUsbTethering(true);
592 private void setUsbTethering(boolean enabled) {
593 ConnectivityManager cm =
594 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
595 mUsbTether.setChecked(false);
596 if (cm.setUsbTethering(enabled) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
597 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
600 mUsbTether.setSummary("");
604 public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
605 ConnectivityManager cm =
606 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
608 if (preference == mUsbTether) {
609 boolean newState = mUsbTether.isChecked();
612 startProvisioningIfNecessary(TETHERING_USB);
614 if (TetherUtil.isProvisioningNeeded(getActivity())) {
615 TetherService.cancelRecheckAlarmIfNecessary(getActivity(), TETHERING_USB);
617 setUsbTethering(newState);
619 } else if (preference == mBluetoothTether) {
620 boolean bluetoothTetherState = mBluetoothTether.isChecked();
622 if (bluetoothTetherState) {
623 startProvisioningIfNecessary(TETHERING_BLUETOOTH);
625 if (TetherUtil.isProvisioningNeeded(getActivity())) {
626 TetherService.cancelRecheckAlarmIfNecessary(getActivity(), TETHERING_BLUETOOTH);
628 boolean errored = false;
630 String [] tethered = cm.getTetheredIfaces();
631 String bluetoothIface = findIface(tethered, mBluetoothRegexs);
632 if (bluetoothIface != null &&
633 cm.untether(bluetoothIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
637 BluetoothPan bluetoothPan = mBluetoothPan.get();
638 if (bluetoothPan != null) bluetoothPan.setBluetoothTethering(false);
640 mBluetoothTether.setSummary(R.string.bluetooth_tethering_errored_subtext);
642 mBluetoothTether.setSummary(R.string.bluetooth_tethering_off_subtext);
645 } else if (preference == mCreateNetwork) {
646 showDialog(DIALOG_AP_SETTINGS);
649 return super.onPreferenceTreeClick(screen, preference);
652 private static String findIface(String[] ifaces, String[] regexes) {
653 for (String iface : ifaces) {
654 for (String regex : regexes) {
655 if (iface.matches(regex)) {
663 public void onClick(DialogInterface dialogInterface, int button) {
664 if (button == DialogInterface.BUTTON_POSITIVE) {
665 mWifiConfig = mDialog.getConfig();
666 if (mWifiConfig != null) {
668 * if soft AP is stopped, bring up
669 * else restart with new config
670 * TODO: update config on a running access point when framework support is added
672 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
673 mWifiManager.setWifiApEnabled(null, false);
674 mWifiManager.setWifiApEnabled(mWifiConfig, true);
676 mWifiManager.setWifiApConfiguration(mWifiConfig);
678 int index = WifiApDialog.getSecurityTypeIndex(mWifiConfig);
679 mCreateNetwork.setSummary(String.format(getActivity().getString(CONFIG_SUBTEXT),
681 mSecurityType[index]));
687 public int getHelpResource() {
688 return R.string.help_url_tether;