Add Ethernet Tethering settings

Add Ethernet Tethering settings
 - Show prefernce if config_ethernet_iface_regex is set
 - Activate if tethered ethernet interface is exist

Bug: 148824036
Test: manual test
 - update prefernce plug-in, plug-out
Change-Id: Ia4f365ddc1a53a926d716046db3e6ac463c978b9
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
index cce2010..c61e573 100644
--- a/src/com/android/settings/TetherSettings.java
+++ b/src/com/android/settings/TetherSettings.java
@@ -18,6 +18,7 @@
 
 import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
 import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
 
 import android.app.Activity;
 import android.app.settings.SettingsEnums;
@@ -31,12 +32,16 @@
 import android.content.pm.PackageManager;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
+import android.net.EthernetManager;
+import android.net.TetheringManager;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.UserManager;
 import android.provider.SearchIndexableResource;
+import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
 
 import androidx.annotation.VisibleForTesting;
@@ -71,6 +76,7 @@
     static final String KEY_USB_TETHER_SETTINGS = "usb_tether_settings";
     @VisibleForTesting
     static final String KEY_ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering";
+    private static final String KEY_ENABLE_ETHERNET_TETHERING = "enable_ethernet_tethering";
     private static final String KEY_DATA_SAVER_FOOTER = "disabled_on_data_saver";
     @VisibleForTesting
     static final String KEY_TETHER_PREFS_FOOTER = "tether_prefs_footer";
@@ -81,15 +87,22 @@
 
     private SwitchPreference mBluetoothTether;
 
+    private SwitchPreference mEthernetTether;
+
     private BroadcastReceiver mTetherChangeReceiver;
 
     private String[] mUsbRegexs;
     private String[] mBluetoothRegexs;
+    private String mEthernetRegex;
     private AtomicReference<BluetoothPan> 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 @@
 
         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 @@
                 mBluetoothTether.setChecked(false);
             }
         }
+        if (!ethernetAvailable) getPreferenceScreen().removePreference(mEthernetTether);
         // Set initial state based on Data Saver mode.
         onDataSaverChanged(mDataSaverBackend.isDataSaverEnabled());
     }
@@ -194,6 +214,7 @@
         mDataSaverEnabled = isDataSaving;
         mUsbTether.setEnabled(!mDataSaverEnabled);
         mBluetoothTether.setEnabled(!mDataSaverEnabled);
+        mEthernetTether.setEnabled(!mDataSaverEnabled);
         mDataSaverFooter.setVisible(mDataSaverEnabled);
     }
 
@@ -221,6 +242,7 @@
         @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<String> available = intent.getStringArrayListExtra(
@@ -279,6 +301,8 @@
         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 @@
 
         if (intent != null) mTetherChangeReceiver.onReceive(activity, intent);
 
+        mEthernetListener = new EthernetListener();
+        mEm.addListener(mEthernetListener);
+
         updateState();
     }
 
@@ -312,8 +339,12 @@
             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 @@
             String[] errored) {
         updateUsbState(available, tethered, errored);
         updateBluetoothState();
+        updateEthernetState(available, tethered);
     }
 
     private void updateUsbState(String[] available, String[] tethered,
@@ -390,6 +422,31 @@
         }
     }
 
+    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 @@
             } 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 @@
                     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 @@
             }
         }
     }
+
+    private final class TetheringEventCallback implements TetheringManager.TetheringEventCallback {
+        @Override
+        public void onTetheredInterfacesChanged(List<String> interfaces) {
+            updateState();
+        }
+    }
+
+    private final class EthernetListener implements EthernetManager.Listener {
+        public void onAvailabilityChanged(String iface, boolean isAvailable) {
+            mHandler.post(TetherSettings.this::updateState);
+        }
+    }
 }