TetherSettings.java revision 436b29e68e6608bed9e8e7d54385b8f62d89208e
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 17package com.android.settings; 18 19import com.android.settings.wifi.WifiApEnabler; 20 21import android.app.Activity; 22import android.app.AlertDialog; 23import android.app.Dialog; 24import android.bluetooth.BluetoothAdapter; 25import android.bluetooth.BluetoothPan; 26import android.bluetooth.BluetoothProfile; 27import android.content.BroadcastReceiver; 28import android.content.Context; 29import android.content.Intent; 30import android.content.IntentFilter; 31import android.content.res.AssetManager; 32import android.net.ConnectivityManager; 33import android.os.Bundle; 34import android.os.Environment; 35import android.preference.CheckBoxPreference; 36import android.preference.Preference; 37import android.preference.PreferenceScreen; 38import android.view.ViewGroup; 39import android.view.ViewParent; 40import android.webkit.WebView; 41 42import java.io.InputStream; 43import java.util.ArrayList; 44import java.util.Locale; 45 46/* 47 * Displays preferences for Tethering. 48 */ 49public class TetherSettings extends SettingsPreferenceFragment { 50 51 private static final String USB_TETHER_SETTINGS = "usb_tether_settings"; 52 private static final String ENABLE_WIFI_AP = "enable_wifi_ap"; 53 private static final String WIFI_AP_SETTINGS = "wifi_ap_settings"; 54 private static final String ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering"; 55 private static final String TETHERING_HELP = "tethering_help"; 56 private static final String USB_HELP_MODIFIER = "usb_"; 57 private static final String WIFI_HELP_MODIFIER = "wifi_"; 58 private static final String HELP_URL = "file:///android_asset/html/%y%z/tethering_%xhelp.html"; 59 private static final String HELP_PATH = "html/%y%z/tethering_help.html"; 60 61 private static final int DIALOG_TETHER_HELP = 1; 62 63 private WebView mView; 64 private CheckBoxPreference mUsbTether; 65 66 private WifiApEnabler mWifiApEnabler; 67 68 private CheckBoxPreference mBluetoothTether; 69 70 private PreferenceScreen mTetherHelp; 71 72 private BroadcastReceiver mTetherChangeReceiver; 73 74 private String[] mUsbRegexs; 75 76 private String[] mWifiRegexs; 77 78 private String[] mBluetoothRegexs; 79 private BluetoothPan mBluetoothPan; 80 81 @Override 82 public void onCreate(Bundle icicle) { 83 super.onCreate(icicle); 84 addPreferencesFromResource(R.xml.tether_prefs); 85 86 final Activity activity = getActivity(); 87 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 88 if (adapter != null) { 89 adapter.getProfileProxy(activity.getApplicationContext(), mProfileServiceListener, 90 BluetoothProfile.PAN); 91 } 92 93 CheckBoxPreference enableWifiAp = 94 (CheckBoxPreference) findPreference(ENABLE_WIFI_AP); 95 Preference wifiApSettings = findPreference(WIFI_AP_SETTINGS); 96 mUsbTether = (CheckBoxPreference) findPreference(USB_TETHER_SETTINGS); 97 mBluetoothTether = (CheckBoxPreference) findPreference(ENABLE_BLUETOOTH_TETHERING); 98 mTetherHelp = (PreferenceScreen) findPreference(TETHERING_HELP); 99 100 ConnectivityManager cm = 101 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 102 103 mUsbRegexs = cm.getTetherableUsbRegexs(); 104 mWifiRegexs = cm.getTetherableWifiRegexs(); 105 mBluetoothRegexs = cm.getTetherableBluetoothRegexs(); 106 107 final boolean usbAvailable = mUsbRegexs.length != 0; 108 final boolean wifiAvailable = mWifiRegexs.length != 0; 109 final boolean bluetoothAvailable = mBluetoothRegexs.length != 0; 110 111 if (!usbAvailable || Utils.isMonkeyRunning()) { 112 getPreferenceScreen().removePreference(mUsbTether); 113 } 114 115 if (!wifiAvailable) { 116 getPreferenceScreen().removePreference(enableWifiAp); 117 getPreferenceScreen().removePreference(wifiApSettings); 118 } 119 120 if (!bluetoothAvailable) { 121 getPreferenceScreen().removePreference(mBluetoothTether); 122 } else { 123 if (mBluetoothPan != null && mBluetoothPan.isTetheringOn()) { 124 mBluetoothTether.setChecked(true); 125 } else { 126 mBluetoothTether.setChecked(false); 127 } 128 } 129 130 mWifiApEnabler = new WifiApEnabler(activity, enableWifiAp); 131 mView = new WebView(activity); 132 } 133 134 private BluetoothProfile.ServiceListener mProfileServiceListener = 135 new BluetoothProfile.ServiceListener() { 136 public void onServiceConnected(int profile, BluetoothProfile proxy) { 137 mBluetoothPan = (BluetoothPan) proxy; 138 } 139 public void onServiceDisconnected(int profile) { 140 mBluetoothPan = null; 141 } 142 }; 143 144 @Override 145 public Dialog onCreateDialog(int id) { 146 if (id == DIALOG_TETHER_HELP) { 147 Locale locale = Locale.getDefault(); 148 149 // check for the full language + country resource, if not there, try just language 150 final AssetManager am = getActivity().getAssets(); 151 String path = HELP_PATH.replace("%y", locale.getLanguage().toLowerCase()); 152 path = path.replace("%z", '_'+locale.getCountry().toLowerCase()); 153 boolean useCountry = true; 154 InputStream is = null; 155 try { 156 is = am.open(path); 157 } catch (Exception ignored) { 158 useCountry = false; 159 } finally { 160 if (is != null) { 161 try { 162 is.close(); 163 } catch (Exception ignored) {} 164 } 165 } 166 String url = HELP_URL.replace("%y", locale.getLanguage().toLowerCase()); 167 url = url.replace("%z", useCountry ? '_'+locale.getCountry().toLowerCase() : ""); 168 if ((mUsbRegexs.length != 0) && (mWifiRegexs.length == 0)) { 169 url = url.replace("%x", USB_HELP_MODIFIER); 170 } else if ((mWifiRegexs.length != 0) && (mUsbRegexs.length == 0)) { 171 url = url.replace("%x", WIFI_HELP_MODIFIER); 172 } else { 173 // could assert that both wifi and usb have regexs, but the default 174 // is to use this anyway so no check is needed 175 url = url.replace("%x", ""); 176 } 177 178 mView.loadUrl(url); 179 // Detach from old parent first 180 ViewParent parent = mView.getParent(); 181 if (parent != null && parent instanceof ViewGroup) { 182 ((ViewGroup) parent).removeView(mView); 183 } 184 return new AlertDialog.Builder(getActivity()) 185 .setCancelable(true) 186 .setTitle(R.string.tethering_help_button_text) 187 .setView(mView) 188 .create(); 189 } 190 return null; 191 } 192 193 private class TetherChangeReceiver extends BroadcastReceiver { 194 @Override 195 public void onReceive(Context content, Intent intent) { 196 if (intent.getAction().equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) { 197 // TODO - this should understand the interface types 198 ArrayList<String> available = intent.getStringArrayListExtra( 199 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 200 ArrayList<String> active = intent.getStringArrayListExtra( 201 ConnectivityManager.EXTRA_ACTIVE_TETHER); 202 ArrayList<String> errored = intent.getStringArrayListExtra( 203 ConnectivityManager.EXTRA_ERRORED_TETHER); 204 updateState(available.toArray(new String[available.size()]), 205 active.toArray(new String[active.size()]), 206 errored.toArray(new String[errored.size()])); 207 } else if (intent.getAction().equals(Intent.ACTION_MEDIA_SHARED) || 208 intent.getAction().equals(Intent.ACTION_MEDIA_UNSHARED)) { 209 updateState(); 210 } else if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { 211 updateState(); 212 } 213 } 214 } 215 216 @Override 217 public void onStart() { 218 super.onStart(); 219 220 final Activity activity = getActivity(); 221 222 mTetherChangeReceiver = new TetherChangeReceiver(); 223 IntentFilter filter = new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED); 224 Intent intent = activity.registerReceiver(mTetherChangeReceiver, filter); 225 226 filter = new IntentFilter(); 227 filter.addAction(Intent.ACTION_MEDIA_SHARED); 228 filter.addAction(Intent.ACTION_MEDIA_UNSHARED); 229 filter.addDataScheme("file"); 230 activity.registerReceiver(mTetherChangeReceiver, filter); 231 232 filter = new IntentFilter(); 233 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 234 activity.registerReceiver(mTetherChangeReceiver, filter); 235 236 if (intent != null) mTetherChangeReceiver.onReceive(activity, intent); 237 mWifiApEnabler.resume(); 238 } 239 240 @Override 241 public void onStop() { 242 super.onStop(); 243 getActivity().unregisterReceiver(mTetherChangeReceiver); 244 mTetherChangeReceiver = null; 245 mWifiApEnabler.pause(); 246 } 247 248 private void updateState() { 249 ConnectivityManager cm = 250 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 251 252 String[] available = cm.getTetherableIfaces(); 253 String[] tethered = cm.getTetheredIfaces(); 254 String[] errored = cm.getTetheringErroredIfaces(); 255 updateState(available, tethered, errored); 256 } 257 258 private void updateState(String[] available, String[] tethered, 259 String[] errored) { 260 updateUsbState(available, tethered, errored); 261 updateBluetoothState(available, tethered, errored); 262 } 263 264 265 private void updateUsbState(String[] available, String[] tethered, 266 String[] errored) { 267 ConnectivityManager cm = 268 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 269 boolean usbAvailable = false; 270 int usbError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 271 boolean massStorageActive = 272 Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState()); 273 for (String s : available) { 274 for (String regex : mUsbRegexs) { 275 if (s.matches(regex)) { 276 usbAvailable = true; 277 if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) { 278 usbError = cm.getLastTetherError(s); 279 } 280 } 281 } 282 } 283 boolean usbTethered = false; 284 for (String s : tethered) { 285 for (String regex : mUsbRegexs) { 286 if (s.matches(regex)) usbTethered = true; 287 } 288 } 289 boolean usbErrored = false; 290 for (String s: errored) { 291 for (String regex : mUsbRegexs) { 292 if (s.matches(regex)) usbErrored = true; 293 } 294 } 295 296 if (usbTethered) { 297 mUsbTether.setSummary(R.string.usb_tethering_active_subtext); 298 mUsbTether.setEnabled(true); 299 mUsbTether.setChecked(true); 300 } else if (usbAvailable) { 301 if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) { 302 mUsbTether.setSummary(R.string.usb_tethering_available_subtext); 303 } else { 304 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext); 305 } 306 mUsbTether.setEnabled(true); 307 mUsbTether.setChecked(false); 308 } else if (usbErrored) { 309 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext); 310 mUsbTether.setEnabled(false); 311 mUsbTether.setChecked(false); 312 } else if (massStorageActive) { 313 mUsbTether.setSummary(R.string.usb_tethering_storage_active_subtext); 314 mUsbTether.setEnabled(false); 315 mUsbTether.setChecked(false); 316 } else { 317 mUsbTether.setSummary(R.string.usb_tethering_unavailable_subtext); 318 mUsbTether.setEnabled(false); 319 mUsbTether.setChecked(false); 320 } 321 } 322 323 private void updateBluetoothState(String[] available, String[] tethered, 324 String[] errored) { 325 ConnectivityManager cm = 326 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 327 int bluetoothError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 328 for (String s : available) { 329 for (String regex : mBluetoothRegexs) { 330 if (s.matches(regex)) { 331 if (bluetoothError == ConnectivityManager.TETHER_ERROR_NO_ERROR) { 332 bluetoothError = cm.getLastTetherError(s); 333 } 334 } 335 } 336 } 337 boolean bluetoothTethered = false; 338 for (String s : tethered) { 339 for (String regex : mBluetoothRegexs) { 340 if (s.matches(regex)) bluetoothTethered = true; 341 } 342 } 343 boolean bluetoothErrored = false; 344 for (String s: errored) { 345 for (String regex : mBluetoothRegexs) { 346 if (s.matches(regex)) bluetoothErrored = true; 347 } 348 } 349 350 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 351 int btState = adapter.getState(); 352 if (btState == BluetoothAdapter.STATE_TURNING_OFF) { 353 mBluetoothTether.setEnabled(false); 354 mBluetoothTether.setSummary(R.string.wifi_stopping); 355 } else if (btState == BluetoothAdapter.STATE_TURNING_ON) { 356 mBluetoothTether.setEnabled(false); 357 mBluetoothTether.setSummary(R.string.bluetooth_turning_on); 358 } else if (mBluetoothPan.isTetheringOn()) { 359 mBluetoothTether.setChecked(true); 360 if (btState == BluetoothAdapter.STATE_ON) { 361 mBluetoothTether.setEnabled(true); 362 if (bluetoothTethered) { 363 mBluetoothTether.setSummary(R.string.bluetooth_tethering_connected_subtext); 364 } else if (bluetoothErrored) { 365 mBluetoothTether.setSummary(R.string.bluetooth_tethering_errored_subtext); 366 } else { 367 mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext); 368 } 369 } 370 } else { 371 mBluetoothTether.setEnabled(true); 372 mBluetoothTether.setChecked(false); 373 mBluetoothTether.setSummary(R.string.bluetooth_tethering_off_subtext); 374 } 375 } 376 377 @Override 378 public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { 379 if (preference == mUsbTether) { 380 boolean newState = mUsbTether.isChecked(); 381 382 ConnectivityManager cm = 383 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 384 385 if (newState) { 386 String[] available = cm.getTetherableIfaces(); 387 388 String usbIface = findIface(available, mUsbRegexs); 389 if (usbIface == null) { 390 updateState(); 391 return true; 392 } 393 if (cm.tether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 394 mUsbTether.setChecked(false); 395 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext); 396 return true; 397 } 398 mUsbTether.setSummary(""); 399 } else { 400 String [] tethered = cm.getTetheredIfaces(); 401 402 String usbIface = findIface(tethered, mUsbRegexs); 403 if (usbIface == null) { 404 updateState(); 405 return true; 406 } 407 if (cm.untether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 408 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext); 409 return true; 410 } 411 mUsbTether.setSummary(""); 412 } 413 } else if(preference == mBluetoothTether) { 414 boolean bluetoothTetherState = mBluetoothTether.isChecked(); 415 416 if (bluetoothTetherState) { 417 // turn on Bluetooth first 418 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 419 if (adapter.getState() == BluetoothAdapter.STATE_OFF) { 420 adapter.enable(); 421 mBluetoothTether.setSummary(R.string.bluetooth_turning_on); 422 mBluetoothTether.setEnabled(false); 423 } 424 425 mBluetoothPan.setBluetoothTethering(true); 426 mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext); 427 } else { 428 boolean errored = false; 429 430 ConnectivityManager cm = 431 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 432 String [] tethered = cm.getTetheredIfaces(); 433 String bluetoothIface = findIface(tethered, mBluetoothRegexs); 434 if (bluetoothIface != null && 435 cm.untether(bluetoothIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 436 errored = true; 437 } 438 439 mBluetoothPan.setBluetoothTethering(false); 440 if (errored) { 441 mBluetoothTether.setSummary(R.string.bluetooth_tethering_errored_subtext); 442 } else { 443 mBluetoothTether.setSummary(R.string.bluetooth_tethering_off_subtext); 444 } 445 } 446 } else if (preference == mTetherHelp) { 447 showDialog(DIALOG_TETHER_HELP); 448 return true; 449 } 450 451 return super.onPreferenceTreeClick(screen, preference); 452 } 453 454 private static String findIface(String[] ifaces, String[] regexes) { 455 for (String iface : ifaces) { 456 for (String regex : regexes) { 457 if (iface.matches(regex)) { 458 return iface; 459 } 460 } 461 } 462 return null; 463 } 464} 465