(This replaces Iaa0f3b25eaadb094a4c3fb4cecbd09e0322aae33) This change removes the need to convert Object[]->String[] for each iteration of each of available,tethered,errored states in updateStatus() by converting these as soon as possible. This fix (and the code before) is strange because each of available,tethered, errored are defined as type ArrayList<String> but intent.getStringArrayListExtra() returns type Object[] dispite its name. Because other calls to updateState() use String[] it seems best to do the conversion outside this method in the Object[] case and thus avoid the per-iteration casting in the Object[] case and the downright wasteful per-iteration String[]->Object[]->String[] casting in the String[] input cases. I've also removed some unused imports and an unused variable. Change-Id: I805ef19aa9ceff7e4fc491623cdcb413ce170798
317 lines
12 KiB
Java
317 lines
12 KiB
Java
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings;
|
|
|
|
import com.android.settings.wifi.WifiApEnabler;
|
|
|
|
import android.app.AlertDialog;
|
|
import android.app.Dialog;
|
|
import android.os.Bundle;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.res.AssetManager;
|
|
import android.net.ConnectivityManager;
|
|
import android.os.Environment;
|
|
import android.preference.CheckBoxPreference;
|
|
import android.preference.Preference;
|
|
import android.preference.PreferenceActivity;
|
|
import android.preference.PreferenceScreen;
|
|
import android.webkit.WebView;
|
|
|
|
import java.io.InputStream;
|
|
import java.util.ArrayList;
|
|
import java.util.Locale;
|
|
|
|
/*
|
|
* Displays preferences for Tethering.
|
|
*/
|
|
public class TetherSettings extends PreferenceActivity {
|
|
private static final String USB_TETHER_SETTINGS = "usb_tether_settings";
|
|
private static final String ENABLE_WIFI_AP = "enable_wifi_ap";
|
|
private static final String WIFI_AP_SETTINGS = "wifi_ap_settings";
|
|
private static final String TETHERING_HELP = "tethering_help";
|
|
private static final String USB_HELP_MODIFIER = "usb_";
|
|
private static final String WIFI_HELP_MODIFIER = "wifi_";
|
|
private static final String HELP_URL = "file:///android_asset/html/%y%z/tethering_%xhelp.html";
|
|
private static final String HELP_PATH = "html/%y%z/tethering_help.html";
|
|
|
|
private static final int DIALOG_TETHER_HELP = 1;
|
|
|
|
private WebView mView;
|
|
private CheckBoxPreference mUsbTether;
|
|
|
|
private CheckBoxPreference mEnableWifiAp;
|
|
private PreferenceScreen mWifiApSettings;
|
|
private WifiApEnabler mWifiApEnabler;
|
|
private PreferenceScreen mTetherHelp;
|
|
|
|
private BroadcastReceiver mTetherChangeReceiver;
|
|
|
|
private String[] mUsbRegexs;
|
|
|
|
private String[] mWifiRegexs;
|
|
|
|
@Override
|
|
protected void onCreate(Bundle icicle) {
|
|
super.onCreate(icicle);
|
|
|
|
addPreferencesFromResource(R.xml.tether_prefs);
|
|
|
|
mEnableWifiAp = (CheckBoxPreference) findPreference(ENABLE_WIFI_AP);
|
|
mWifiApSettings = (PreferenceScreen) findPreference(WIFI_AP_SETTINGS);
|
|
mUsbTether = (CheckBoxPreference) findPreference(USB_TETHER_SETTINGS);
|
|
mTetherHelp = (PreferenceScreen) findPreference(TETHERING_HELP);
|
|
|
|
ConnectivityManager cm =
|
|
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
|
|
mUsbRegexs = cm.getTetherableUsbRegexs();
|
|
if (mUsbRegexs.length == 0) {
|
|
getPreferenceScreen().removePreference(mUsbTether);
|
|
|
|
setTitle(R.string.tether_settings_title_wifi);
|
|
}
|
|
|
|
mWifiRegexs = cm.getTetherableWifiRegexs();
|
|
if (mWifiRegexs.length == 0) {
|
|
getPreferenceScreen().removePreference(mEnableWifiAp);
|
|
getPreferenceScreen().removePreference(mWifiApSettings);
|
|
|
|
setTitle(R.string.tether_settings_title_usb);
|
|
} else if (mUsbRegexs.length != 0) {
|
|
// have both
|
|
setTitle(R.string.tether_settings_title_both);
|
|
}
|
|
mWifiApEnabler = new WifiApEnabler(this, mEnableWifiAp);
|
|
mView = new WebView(this);
|
|
}
|
|
|
|
@Override
|
|
protected Dialog onCreateDialog(int id) {
|
|
if (id == DIALOG_TETHER_HELP) {
|
|
Locale locale = Locale.getDefault();
|
|
|
|
// check for the full language + country resource, if not there, try just language
|
|
AssetManager am = getAssets();
|
|
String path = HELP_PATH.replace("%y", locale.getLanguage().toLowerCase());
|
|
path = path.replace("%z", "_"+locale.getCountry().toLowerCase());
|
|
boolean useCountry = true;
|
|
InputStream is = null;
|
|
try {
|
|
is = am.open(path);
|
|
} catch (Exception e) {
|
|
useCountry = false;
|
|
} finally {
|
|
if (is != null) {
|
|
try {
|
|
is.close();
|
|
} catch (Exception e) {}
|
|
}
|
|
}
|
|
String url = HELP_URL.replace("%y", locale.getLanguage().toLowerCase());
|
|
url = url.replace("%z", (useCountry ? "_"+locale.getCountry().toLowerCase() : ""));
|
|
if ((mUsbRegexs.length != 0) && (mWifiRegexs.length == 0)) {
|
|
url = url.replace("%x", USB_HELP_MODIFIER);
|
|
} else if ((mWifiRegexs.length != 0) && (mUsbRegexs.length == 0)) {
|
|
url = url.replace("%x", WIFI_HELP_MODIFIER);
|
|
} else {
|
|
// could assert that both wifi and usb have regexs, but the default
|
|
// is to use this anyway so no check is needed
|
|
url = url.replace("%x", "");
|
|
}
|
|
|
|
mView.loadUrl(url);
|
|
|
|
return new AlertDialog.Builder(this)
|
|
.setCancelable(true)
|
|
.setTitle(R.string.tethering_help_button_text)
|
|
.setView(mView)
|
|
.create();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private class TetherChangeReceiver extends BroadcastReceiver {
|
|
public void onReceive(Context content, Intent intent) {
|
|
if (intent.getAction().equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
|
|
// TODO - this should understand the interface types
|
|
ArrayList<String> available = intent.getStringArrayListExtra(
|
|
ConnectivityManager.EXTRA_AVAILABLE_TETHER);
|
|
ArrayList<String> active = intent.getStringArrayListExtra(
|
|
ConnectivityManager.EXTRA_ACTIVE_TETHER);
|
|
ArrayList<String> errored = intent.getStringArrayListExtra(
|
|
ConnectivityManager.EXTRA_ERRORED_TETHER);
|
|
updateState((String[]) available.toArray(), (String[]) active.toArray(),
|
|
(String[]) errored.toArray());
|
|
} else if (intent.getAction().equals(Intent.ACTION_MEDIA_SHARED) ||
|
|
intent.getAction().equals(Intent.ACTION_MEDIA_UNSHARED)) {
|
|
updateState();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
|
|
IntentFilter filter = new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
|
|
mTetherChangeReceiver = new TetherChangeReceiver();
|
|
Intent intent = registerReceiver(mTetherChangeReceiver, filter);
|
|
|
|
filter = new IntentFilter();
|
|
filter.addAction(Intent.ACTION_MEDIA_SHARED);
|
|
filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
|
|
filter.addDataScheme("file");
|
|
registerReceiver(mTetherChangeReceiver, filter);
|
|
|
|
if (intent != null) mTetherChangeReceiver.onReceive(this, intent);
|
|
mWifiApEnabler.resume();
|
|
}
|
|
|
|
@Override
|
|
protected void onPause() {
|
|
super.onPause();
|
|
unregisterReceiver(mTetherChangeReceiver);
|
|
mTetherChangeReceiver = null;
|
|
mWifiApEnabler.pause();
|
|
}
|
|
|
|
private void updateState() {
|
|
ConnectivityManager cm =
|
|
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
|
|
String[] available = cm.getTetherableIfaces();
|
|
String[] tethered = cm.getTetheredIfaces();
|
|
String[] errored = cm.getTetheringErroredIfaces();
|
|
updateState(available, tethered, errored);
|
|
}
|
|
|
|
private void updateState(String[] available, String[] tethered,
|
|
String[] errored) {
|
|
ConnectivityManager cm =
|
|
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
boolean usbTethered = false;
|
|
boolean usbAvailable = false;
|
|
int usbError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
|
boolean usbErrored = false;
|
|
boolean massStorageActive =
|
|
Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState());
|
|
for (String s : available) {
|
|
for (String regex : mUsbRegexs) {
|
|
if (s.matches(regex)) {
|
|
usbAvailable = true;
|
|
if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
|
|
usbError = cm.getLastTetherError(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (String s : tethered) {
|
|
for (String regex : mUsbRegexs) {
|
|
if (s.matches(regex)) usbTethered = true;
|
|
}
|
|
}
|
|
for (String s: errored) {
|
|
for (String regex : mUsbRegexs) {
|
|
if (s.matches(regex)) usbErrored = true;
|
|
}
|
|
}
|
|
|
|
if (usbTethered) {
|
|
mUsbTether.setSummary(R.string.usb_tethering_active_subtext);
|
|
mUsbTether.setEnabled(true);
|
|
mUsbTether.setChecked(true);
|
|
} else if (usbAvailable) {
|
|
if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
|
|
mUsbTether.setSummary(R.string.usb_tethering_available_subtext);
|
|
} else {
|
|
mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
|
|
}
|
|
mUsbTether.setEnabled(true);
|
|
mUsbTether.setChecked(false);
|
|
} else if (usbErrored) {
|
|
mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
|
|
mUsbTether.setEnabled(false);
|
|
mUsbTether.setChecked(false);
|
|
} else if (massStorageActive) {
|
|
mUsbTether.setSummary(R.string.usb_tethering_storage_active_subtext);
|
|
mUsbTether.setEnabled(false);
|
|
mUsbTether.setChecked(false);
|
|
} else {
|
|
mUsbTether.setSummary(R.string.usb_tethering_unavailable_subtext);
|
|
mUsbTether.setEnabled(false);
|
|
mUsbTether.setChecked(false);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
|
|
if (preference == mUsbTether) {
|
|
boolean newState = mUsbTether.isChecked();
|
|
|
|
ConnectivityManager cm =
|
|
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
|
|
if (newState) {
|
|
String[] available = cm.getTetherableIfaces();
|
|
|
|
String usbIface = findIface(available, mUsbRegexs);
|
|
if (usbIface == null) {
|
|
updateState();
|
|
return true;
|
|
}
|
|
if (cm.tether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
|
|
mUsbTether.setChecked(false);
|
|
mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
|
|
return true;
|
|
}
|
|
mUsbTether.setSummary("");
|
|
} else {
|
|
String [] tethered = cm.getTetheredIfaces();
|
|
|
|
String usbIface = findIface(tethered, mUsbRegexs);
|
|
if (usbIface == null) {
|
|
updateState();
|
|
return true;
|
|
}
|
|
if (cm.untether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
|
|
mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
|
|
return true;
|
|
}
|
|
mUsbTether.setSummary("");
|
|
}
|
|
} else if (preference == mTetherHelp) {
|
|
|
|
showDialog(DIALOG_TETHER_HELP);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private String findIface(String[] ifaces, String[] regexes) {
|
|
for (String iface : ifaces) {
|
|
for (String regex : regexes) {
|
|
if (iface.matches(regex)) {
|
|
return iface;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|