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 com.android.settings.wifi.WifiApEnabler; 20 21 import android.app.AlertDialog; 22 import android.app.Dialog; 23 import android.os.Bundle; 24 import android.os.SystemProperties; 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.res.AssetManager; 30 import android.net.ConnectivityManager; 31 import android.os.Environment; 32 import android.preference.CheckBoxPreference; 33 import android.preference.Preference; 34 import android.preference.PreferenceActivity; 35 import android.preference.PreferenceScreen; 36 import android.provider.Settings; 37 import android.util.Log; 38 import android.webkit.WebView; 39 40 import java.io.InputStream; 41 import java.util.ArrayList; 42 import java.util.Locale; 43 44 /* 45 * Displays preferences for Tethering. 46 */ 47 public class TetherSettings extends PreferenceActivity { 48 private static final String USB_TETHER_SETTINGS = "usb_tether_settings"; 49 private static final String ENABLE_WIFI_AP = "enable_wifi_ap"; 50 private static final String WIFI_AP_SETTINGS = "wifi_ap_settings"; 51 private static final String TETHERING_HELP = "tethering_help"; 52 private static final String USB_HELP_MODIFIER = "usb_"; 53 private static final String WIFI_HELP_MODIFIER = "wifi_"; 54 private static final String HELP_URL = "file:///android_asset/html/%y%z/tethering_%xhelp.html"; 55 private static final String HELP_PATH = "html/%y%z/tethering_help.html"; 56 57 private static final int DIALOG_TETHER_HELP = 1; 58 59 private WebView mView; 60 private CheckBoxPreference mUsbTether; 61 62 private CheckBoxPreference mEnableWifiAp; 63 private PreferenceScreen mWifiApSettings; 64 private WifiApEnabler mWifiApEnabler; 65 private PreferenceScreen mTetherHelp; 66 67 private BroadcastReceiver mTetherChangeReceiver; 68 69 private String[] mUsbRegexs; 70 private ArrayList mUsbIfaces; 71 72 private String[] mWifiRegexs; 73 74 @Override 75 protected void onCreate(Bundle icicle) { 76 super.onCreate(icicle); 77 78 addPreferencesFromResource(R.xml.tether_prefs); 79 80 mEnableWifiAp = (CheckBoxPreference) findPreference(ENABLE_WIFI_AP); 81 mWifiApSettings = (PreferenceScreen) findPreference(WIFI_AP_SETTINGS); 82 mUsbTether = (CheckBoxPreference) findPreference(USB_TETHER_SETTINGS); 83 mTetherHelp = (PreferenceScreen) findPreference(TETHERING_HELP); 84 85 ConnectivityManager cm = 86 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 87 88 mUsbRegexs = cm.getTetherableUsbRegexs(); 89 if (mUsbRegexs.length == 0) { 90 getPreferenceScreen().removePreference(mUsbTether); 91 92 setTitle(R.string.tether_settings_title_wifi); 93 } 94 95 mWifiRegexs = cm.getTetherableWifiRegexs(); 96 if (mWifiRegexs.length == 0) { 97 getPreferenceScreen().removePreference(mEnableWifiAp); 98 getPreferenceScreen().removePreference(mWifiApSettings); 99 100 setTitle(R.string.tether_settings_title_usb); 101 } else if (mUsbRegexs.length != 0) { 102 // have both 103 setTitle(R.string.tether_settings_title_both); 104 } 105 mWifiApEnabler = new WifiApEnabler(this, mEnableWifiAp); 106 mView = new WebView(this); 107 } 108 109 @Override 110 protected Dialog onCreateDialog(int id) { 111 if (id == DIALOG_TETHER_HELP) { 112 Locale locale = Locale.getDefault(); 113 114 // check for the full language + country resource, if not there, try just language 115 AssetManager am = getAssets(); 116 String path = HELP_PATH.replace("%y", locale.getLanguage().toLowerCase()); 117 path = path.replace("%z", "_"+locale.getCountry().toLowerCase()); 118 boolean useCountry = true; 119 InputStream is = null; 120 try { 121 is = am.open(path); 122 } catch (Exception e) { 123 useCountry = false; 124 } finally { 125 if (is != null) { 126 try { 127 is.close(); 128 } catch (Exception e) {} 129 } 130 } 131 String url = HELP_URL.replace("%y", locale.getLanguage().toLowerCase()); 132 url = url.replace("%z", (useCountry ? "_"+locale.getCountry().toLowerCase() : "")); 133 if ((mUsbRegexs.length != 0) && (mWifiRegexs.length == 0)) { 134 url = url.replace("%x", USB_HELP_MODIFIER); 135 } else if ((mWifiRegexs.length != 0) && (mUsbRegexs.length == 0)) { 136 url = url.replace("%x", WIFI_HELP_MODIFIER); 137 } else { 138 // could assert that both wifi and usb have regexs, but the default 139 // is to use this anyway so no check is needed 140 url = url.replace("%x", ""); 141 } 142 143 mView.loadUrl(url); 144 145 return new AlertDialog.Builder(this) 146 .setCancelable(true) 147 .setTitle(R.string.tethering_help_button_text) 148 .setView(mView) 149 .create(); 150 } 151 return null; 152 } 153 154 private class TetherChangeReceiver extends BroadcastReceiver { 155 public void onReceive(Context content, Intent intent) { 156 if (intent.getAction().equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) { 157 // TODO - this should understand the interface types 158 ArrayList<String> available = intent.getStringArrayListExtra( 159 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 160 ArrayList<String> active = intent.getStringArrayListExtra( 161 ConnectivityManager.EXTRA_ACTIVE_TETHER); 162 ArrayList<String> errored = intent.getStringArrayListExtra( 163 ConnectivityManager.EXTRA_ERRORED_TETHER); 164 updateState(available.toArray(), active.toArray(), errored.toArray()); 165 } else if (intent.getAction().equals(Intent.ACTION_MEDIA_SHARED) || 166 intent.getAction().equals(Intent.ACTION_MEDIA_UNSHARED)) { 167 updateState(); 168 } 169 } 170 } 171 172 @Override 173 protected void onResume() { 174 super.onResume(); 175 176 IntentFilter filter = new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED); 177 mTetherChangeReceiver = new TetherChangeReceiver(); 178 Intent intent = registerReceiver(mTetherChangeReceiver, filter); 179 180 filter = new IntentFilter(); 181 filter.addAction(Intent.ACTION_MEDIA_SHARED); 182 filter.addAction(Intent.ACTION_MEDIA_UNSHARED); 183 filter.addDataScheme("file"); 184 registerReceiver(mTetherChangeReceiver, filter); 185 186 if (intent != null) mTetherChangeReceiver.onReceive(this, intent); 187 mWifiApEnabler.resume(); 188 } 189 190 @Override 191 protected void onPause() { 192 super.onPause(); 193 unregisterReceiver(mTetherChangeReceiver); 194 mTetherChangeReceiver = null; 195 mWifiApEnabler.pause(); 196 } 197 198 private void updateState() { 199 ConnectivityManager cm = 200 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 201 202 String[] available = cm.getTetherableIfaces(); 203 String[] tethered = cm.getTetheredIfaces(); 204 String[] errored = cm.getTetheringErroredIfaces(); 205 updateState(available, tethered, errored); 206 } 207 208 private void updateState(Object[] available, Object[] tethered, 209 Object[] errored) { 210 ConnectivityManager cm = 211 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 212 boolean usbTethered = false; 213 boolean usbAvailable = false; 214 int usbError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 215 boolean usbErrored = false; 216 boolean massStorageActive = 217 Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState()); 218 for (Object o : available) { 219 String s = (String)o; 220 for (String regex : mUsbRegexs) { 221 if (s.matches(regex)) { 222 usbAvailable = true; 223 if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) { 224 usbError = cm.getLastTetherError(s); 225 } 226 } 227 } 228 } 229 for (Object o : tethered) { 230 String s = (String)o; 231 for (String regex : mUsbRegexs) { 232 if (s.matches(regex)) usbTethered = true; 233 } 234 } 235 for (Object o: errored) { 236 String s = (String)o; 237 for (String regex : mUsbRegexs) { 238 if (s.matches(regex)) usbErrored = true; 239 } 240 } 241 242 if (usbTethered) { 243 mUsbTether.setSummary(R.string.usb_tethering_active_subtext); 244 mUsbTether.setEnabled(true); 245 mUsbTether.setChecked(true); 246 } else if (usbAvailable) { 247 if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) { 248 mUsbTether.setSummary(R.string.usb_tethering_available_subtext); 249 } else { 250 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext); 251 } 252 mUsbTether.setEnabled(true); 253 mUsbTether.setChecked(false); 254 } else if (usbErrored) { 255 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext); 256 mUsbTether.setEnabled(false); 257 mUsbTether.setChecked(false); 258 } else if (massStorageActive) { 259 mUsbTether.setSummary(R.string.usb_tethering_storage_active_subtext); 260 mUsbTether.setEnabled(false); 261 mUsbTether.setChecked(false); 262 } else { 263 mUsbTether.setSummary(R.string.usb_tethering_unavailable_subtext); 264 mUsbTether.setEnabled(false); 265 mUsbTether.setChecked(false); 266 } 267 } 268 269 @Override 270 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 271 if (preference == mUsbTether) { 272 boolean newState = mUsbTether.isChecked(); 273 274 ConnectivityManager cm = 275 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 276 277 if (newState) { 278 String[] available = cm.getTetherableIfaces(); 279 280 String usbIface = findIface(available, mUsbRegexs); 281 if (usbIface == null) { 282 updateState(); 283 return true; 284 } 285 if (cm.tether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 286 mUsbTether.setChecked(false); 287 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext); 288 return true; 289 } 290 mUsbTether.setSummary(""); 291 } else { 292 String [] tethered = cm.getTetheredIfaces(); 293 294 String usbIface = findIface(tethered, mUsbRegexs); 295 if (usbIface == null) { 296 updateState(); 297 return true; 298 } 299 if (cm.untether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 300 mUsbTether.setSummary(R.string.usb_tethering_errored_subtext); 301 return true; 302 } 303 mUsbTether.setSummary(""); 304 } 305 } else if (preference == mTetherHelp) { 306 307 showDialog(DIALOG_TETHER_HELP); 308 } 309 return false; 310 } 311 312 private String findIface(String[] ifaces, String[] regexes) { 313 for (String iface : ifaces) { 314 for (String regex : regexes) { 315 if (iface.matches(regex)) { 316 return iface; 317 } 318 } 319 } 320 return null; 321 } 322 } 323