Update Tethering.

Adds telephony support, async model, multiple tethered iface suport,
better notifications, device config.

bug:2413855
This commit is contained in:
Robert Greenwalt
2010-02-11 18:18:40 -08:00
parent be16be13c6
commit 2a091d7aa0
8 changed files with 1336 additions and 212 deletions

View File

@@ -125,13 +125,21 @@ public class ConnectivityManager
/**
* @hide
* gives a String[]
*/
public static final String EXTRA_AVAILABLE_TETHER_COUNT = "availableCount";
public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
/**
* @hide
* gives a String[]
*/
public static final String EXTRA_ACTIVE_TETHER_COUNT = "activeCount";
public static final String EXTRA_ACTIVE_TETHER = "activeArray";
/**
* @hide
* gives a String[]
*/
public static final String EXTRA_ERRORED_TETHER = "erroredArray";
/**
* The Default Mobile data connection. When active, all data traffic
@@ -400,4 +408,37 @@ public class ConnectivityManager
return false;
}
}
/**
* {@hide}
*/
public boolean isTetheringSupported() {
try {
return mService.isTetheringSupported();
} catch (RemoteException e) {
return false;
}
}
/**
* {@hide}
*/
public String[] getTetherableUsbRegexs() {
try {
return mService.getTetherableUsbRegexs();
} catch (RemoteException e) {
return new String[0];
}
}
/**
* {@hide}
*/
public String[] getTetherableWifiRegexs() {
try {
return mService.getTetherableWifiRegexs();
} catch (RemoteException e) {
return new String[0];
}
}
}

View File

@@ -55,7 +55,13 @@ interface IConnectivityManager
boolean untether(String iface);
boolean isTetheringSupported();
String[] getTetherableIfaces();
String[] getTetheredIfaces();
String[] getTetherableUsbRegexs();
String[] getTetherableWifiRegexs();
}

View File

@@ -2209,6 +2209,12 @@ public final class Settings {
*/
public static final String NETWORK_PREFERENCE = "network_preference";
/**
* Used to disable Tethering on a device - defaults to true
* @hide
*/
public static final String TETHER_SUPPORTED = "tether_supported";
/**
* No longer supported.
*/

View File

@@ -32,16 +32,19 @@ import android.widget.Toast;
import android.util.Log;
/**
* This activity is shown to the user for him/her to connect/disconnect a Tether
* connection. It will display notification when a suitable connection is made
* to allow the tether to be setup. A second notification will be show when a
* tether is active, allowing the user to manage tethered connections.
* This activity is shown to the user in two cases: when a connection is possible via
* a usb tether and when any type of tether is connected. In the connecting case
* It allows them to start a USB tether. In the Tethered/disconnecting case it
* will disconnect all tethers.
*/
public class TetherActivity extends AlertActivity implements
DialogInterface.OnClickListener {
private static final int POSITIVE_BUTTON = AlertDialog.BUTTON1;
// count of the number of tethered connections at activity create time.
private int mTethered;
/* Used to detect when the USB cable is unplugged, so we can call finish() */
private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
@Override
@@ -52,8 +55,6 @@ public class TetherActivity extends AlertActivity implements
}
};
private boolean mWantTethering;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -61,17 +62,18 @@ public class TetherActivity extends AlertActivity implements
// determine if we advertise tethering or untethering
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm.getTetheredIfaces().length > 0) {
mWantTethering = false;
} else if (cm.getTetherableIfaces().length > 0) {
mWantTethering = true;
} else {
mTethered = cm.getTetheredIfaces().length;
int tetherable = cm.getTetherableIfaces().length;
if ((mTethered == 0) && (tetherable == 0)) {
finish();
return;
}
// Set up the "dialog"
if (mWantTethering == true) {
// Set up the dialog
// if we have a tethered connection we put up a "Do you want to Disconect" dialog
// otherwise we must have a tetherable interface (else we'd return above)
// and so we want to put up the "do you want to connect" dialog
if (mTethered == 0) {
mAlertParams.mIconId = com.android.internal.R.drawable.ic_dialog_usb;
mAlertParams.mTitle = getString(com.android.internal.R.string.tether_title);
mAlertParams.mMessage = getString(com.android.internal.R.string.tether_message);
@@ -114,17 +116,36 @@ public class TetherActivity extends AlertActivity implements
* {@inheritDoc}
*/
public void onClick(DialogInterface dialog, int which) {
boolean error = false;
if (which == POSITIVE_BUTTON) {
ConnectivityManager connManager =
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
// start/stop tethering
if (mWantTethering) {
if (!connManager.tether("ppp0")) {
String[] tethered = cm.getTetheredIfaces();
if (tethered.length == 0) {
String[] tetherable = cm.getTetherableIfaces();
String[] usbRegexs = cm.getTetherableUsbRegexs();
for (String t : tetherable) {
for (String r : usbRegexs) {
if (t.matches(r)) {
if (!cm.tether(t))
error = true;
break;
}
}
}
if (error) {
showTetheringError();
}
} else {
if (!connManager.untether("ppp0")) {
for (String t : tethered) {
if (!cm.untether("ppp0")) {
error = true;
}
}
if (error) {
showUnTetheringError();
}
}
@@ -134,7 +155,12 @@ public class TetherActivity extends AlertActivity implements
}
private void handleTetherStateChanged(Intent intent) {
finish();
// determine if we advertise tethering or untethering
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
if (mTethered != cm.getTetheredIfaces().length) {
finish();
}
}
private void showTetheringError() {

View File

@@ -1021,7 +1021,7 @@ public class HierarchicalStateMachine {
* @param msg that couldn't be handled.
*/
protected void unhandledMessage(Message msg) {
Log.e(TAG, "unhandledMessage: msg.what=" + msg.what);
Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
}
/**

View File

@@ -70,6 +70,22 @@
<item>"0,1"</item>
</string-array>
<!-- List of regexpressions describing the interface (if any) that represent tetherable
USB interfaces. If the device doesn't want to support tething over USB this should
be empty. An example would be "usb.*" -->
<string-array translatable="false" name="config_tether_usb_regexs">
</string-array>
<!-- List of regexpressions describing the interface (if any) that represent tetherable
Wifi interfaces. If the device doesn't want to support tethering over Wifi this
should be empty. An example would be "softap.*" -->
<string-array translatable="false" name="config_tether_wifi_regexs">
</string-array>
<!-- Dhcp range (min, max) to use for tethering purposes -->
<string-array name="config_tether_dhcp_range">
</string-array>
<!-- Flag indicating whether the keyguard should be bypassed when
the slider is open. This can be set or unset depending how easily
the slider can be opened (for example, in a pocket or purse). -->

View File

@@ -798,6 +798,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
"ConnectivityService");
}
private void enforceTetherAccessPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE,
"ConnectivityService");
}
/**
* Handle a {@code DISCONNECTED} event. If this pertains to the non-active
* network, we ignore it. If it is for the active network, we send out a
@@ -1289,6 +1295,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
pw.println(requester.toString());
}
pw.println();
mTethering.dump(fd, pw, args);
}
// must be stateless - things change under us.
@@ -1386,24 +1394,54 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// javadoc from interface
public boolean tether(String iface) {
enforceTetherChangePermission();
return mTethering.tether(iface);
return isTetheringSupported() && mTethering.tether(iface);
}
// javadoc from interface
public boolean untether(String iface) {
enforceTetherChangePermission();
return mTethering.untether(iface);
return isTetheringSupported() && mTethering.untether(iface);
}
// TODO - proper iface API for selection by property, inspection, etc
public String[] getTetherableUsbRegexs() {
enforceTetherAccessPermission();
if (isTetheringSupported()) {
return mTethering.getTetherableUsbRegexs();
} else {
return new String[0];
}
}
public String[] getTetherableWifiRegexs() {
enforceTetherAccessPermission();
if (isTetheringSupported()) {
return mTethering.getTetherableWifiRegexs();
} else {
return new String[0];
}
}
// TODO - move iface listing, queries, etc to new module
// javadoc from interface
public String[] getTetherableIfaces() {
enforceAccessPermission();
enforceTetherAccessPermission();
return mTethering.getTetherableIfaces();
}
public String[] getTetheredIfaces() {
enforceAccessPermission();
enforceTetherAccessPermission();
return mTethering.getTetheredIfaces();
}
// if ro.tether.denied = true we default to no tethering
// gservices could set the secure setting to 1 though to enable it on a build where it
// had previously been turned off.
public boolean isTetheringSupported() {
enforceTetherAccessPermission();
int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
return ((Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0) &&
(mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null));
}
}

File diff suppressed because it is too large Load Diff