Update Tethering.
Adds telephony support, async model, multiple tethered iface suport, better notifications, device config. bug:2413855
This commit is contained in:
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,13 @@ interface IConnectivityManager
|
||||
|
||||
boolean untether(String iface);
|
||||
|
||||
boolean isTetheringSupported();
|
||||
|
||||
String[] getTetherableIfaces();
|
||||
|
||||
String[] getTetheredIfaces();
|
||||
|
||||
String[] getTetherableUsbRegexs();
|
||||
|
||||
String[] getTetherableWifiRegexs();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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). -->
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user