diff --git a/res/values/strings.xml b/res/values/strings.xml
index a695b1ace40..d01f8be555a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3812,6 +3812,12 @@
%1$s will be untethered.
+
+
+ Ethernet tethering
+
+ Share phone\u2019s internet connection via USB Ethernet
+
Use hotspot and tethering to provide internet to other devices through your mobile data connection. Apps can also create a hotspot to share content with nearby devices.
diff --git a/res/xml/tether_prefs.xml b/res/xml/tether_prefs.xml
index abc49cc9ff9..9367a9bbf62 100644
--- a/res/xml/tether_prefs.xml
+++ b/res/xml/tether_prefs.xml
@@ -38,6 +38,12 @@
android:summary="@string/bluetooth_tethering_subtext"
settings:keywords="@string/keywords_hotspot_tethering" />
+
+
mBluetoothPan = new AtomicReference<>();
private Handler mHandler = new Handler();
private OnStartTetheringCallback mStartTetheringCallback;
private ConnectivityManager mCm;
+ private EthernetManager mEm;
+ private TetheringManager mTm;
+ private TetheringEventCallback mTetheringEventCallback;
+ private EthernetListener mEthernetListener;
private WifiTetherPreferenceController mWifiTetherPreferenceController;
@@ -144,17 +157,23 @@ public class TetherSettings extends RestrictedSettingsFragment
mUsbTether = (SwitchPreference) findPreference(KEY_USB_TETHER_SETTINGS);
mBluetoothTether = (SwitchPreference) findPreference(KEY_ENABLE_BLUETOOTH_TETHERING);
+ mEthernetTether = (SwitchPreference) findPreference(KEY_ENABLE_ETHERNET_TETHERING);
setFooterPreferenceTitle();
mDataSaverBackend.addListener(this);
mCm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ mEm = (EthernetManager) getSystemService(Context.ETHERNET_SERVICE);
+ mTm = (TetheringManager) getSystemService(Context.TETHERING_SERVICE);
mUsbRegexs = mCm.getTetherableUsbRegexs();
mBluetoothRegexs = mCm.getTetherableBluetoothRegexs();
+ mEthernetRegex = getContext().getResources().getString(
+ com.android.internal.R.string.config_ethernet_iface_regex);
final boolean usbAvailable = mUsbRegexs.length != 0;
final boolean bluetoothAvailable = mBluetoothRegexs.length != 0;
+ final boolean ethernetAvailable = !TextUtils.isEmpty(mEthernetRegex);
if (!usbAvailable || Utils.isMonkeyRunning()) {
getPreferenceScreen().removePreference(mUsbTether);
@@ -172,6 +191,7 @@ public class TetherSettings extends RestrictedSettingsFragment
mBluetoothTether.setChecked(false);
}
}
+ if (!ethernetAvailable) getPreferenceScreen().removePreference(mEthernetTether);
// Set initial state based on Data Saver mode.
onDataSaverChanged(mDataSaverBackend.isDataSaverEnabled());
}
@@ -194,6 +214,7 @@ public class TetherSettings extends RestrictedSettingsFragment
mDataSaverEnabled = isDataSaving;
mUsbTether.setEnabled(!mDataSaverEnabled);
mBluetoothTether.setEnabled(!mDataSaverEnabled);
+ mEthernetTether.setEnabled(!mDataSaverEnabled);
mDataSaverFooter.setVisible(mDataSaverEnabled);
}
@@ -221,6 +242,7 @@ public class TetherSettings extends RestrictedSettingsFragment
@Override
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
+ // TODO: stop using ACTION_TETHER_STATE_CHANGED and use mTetheringEventCallback instead.
if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
// TODO - this should understand the interface types
ArrayList available = intent.getStringArrayListExtra(
@@ -279,6 +301,8 @@ public class TetherSettings extends RestrictedSettingsFragment
final Activity activity = getActivity();
mStartTetheringCallback = new OnStartTetheringCallback(this);
+ mTetheringEventCallback = new TetheringEventCallback();
+ mTm.registerTetheringEventCallback(new HandlerExecutor(mHandler), mTetheringEventCallback);
mMassStorageActive = Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState());
mTetherChangeReceiver = new TetherChangeReceiver();
@@ -301,6 +325,9 @@ public class TetherSettings extends RestrictedSettingsFragment
if (intent != null) mTetherChangeReceiver.onReceive(activity, intent);
+ mEthernetListener = new EthernetListener();
+ mEm.addListener(mEthernetListener);
+
updateState();
}
@@ -312,8 +339,12 @@ public class TetherSettings extends RestrictedSettingsFragment
return;
}
getActivity().unregisterReceiver(mTetherChangeReceiver);
+ mTm.unregisterTetheringEventCallback(mTetheringEventCallback);
+ mEm.removeListener(mEthernetListener);
mTetherChangeReceiver = null;
mStartTetheringCallback = null;
+ mTetheringEventCallback = null;
+ mEthernetListener = null;
}
private void updateState() {
@@ -327,6 +358,7 @@ public class TetherSettings extends RestrictedSettingsFragment
String[] errored) {
updateUsbState(available, tethered, errored);
updateBluetoothState();
+ updateEthernetState(available, tethered);
}
private void updateUsbState(String[] available, String[] tethered,
@@ -390,6 +422,31 @@ public class TetherSettings extends RestrictedSettingsFragment
}
}
+ private void updateEthernetState(String[] available, String[] tethered) {
+
+ boolean isAvailable = false;
+ boolean isTethered = false;
+
+ for (String s : available) {
+ if (s.matches(mEthernetRegex)) isAvailable = true;
+ }
+
+ for (String s : tethered) {
+ if (s.matches(mEthernetRegex)) isTethered = true;
+ }
+
+ if (isTethered) {
+ mEthernetTether.setEnabled(!mDataSaverEnabled);
+ mEthernetTether.setChecked(true);
+ } else if (isAvailable || mEm.isAvailable()) {
+ mEthernetTether.setEnabled(!mDataSaverEnabled);
+ mEthernetTether.setChecked(false);
+ } else {
+ mEthernetTether.setEnabled(false);
+ mEthernetTether.setChecked(false);
+ }
+ }
+
public static boolean isProvisioningNeededButUnavailable(Context context) {
return (TetherUtil.isProvisioningNeeded(context)
&& !isIntentAvailable(context));
@@ -438,6 +495,12 @@ public class TetherSettings extends RestrictedSettingsFragment
} else {
mCm.stopTethering(TETHERING_BLUETOOTH);
}
+ } else if (preference == mEthernetTether) {
+ if (mEthernetTether.isChecked()) {
+ startTethering(TETHERING_ETHERNET);
+ } else {
+ mCm.stopTethering(TETHERING_ETHERNET);
+ }
}
return super.onPreferenceTreeClick(preference);
@@ -495,6 +558,13 @@ public class TetherSettings extends RestrictedSettingsFragment
if (!bluetoothAvailable) {
keys.add(KEY_ENABLE_BLUETOOTH_TETHERING);
}
+
+ final boolean ethernetAvailable = !TextUtils.isEmpty(
+ context.getResources().getString(
+ com.android.internal.R.string.config_ethernet_iface_regex));
+ if (!ethernetAvailable) {
+ keys.add(KEY_ENABLE_ETHERNET_TETHERING);
+ }
return keys;
}
};
@@ -524,4 +594,17 @@ public class TetherSettings extends RestrictedSettingsFragment
}
}
}
+
+ private final class TetheringEventCallback implements TetheringManager.TetheringEventCallback {
+ @Override
+ public void onTetheredInterfacesChanged(List interfaces) {
+ updateState();
+ }
+ }
+
+ private final class EthernetListener implements EthernetManager.Listener {
+ public void onAvailabilityChanged(String iface, boolean isAvailable) {
+ mHandler.post(TetherSettings.this::updateState);
+ }
+ }
}