Display one row item per Ethernet interface

This change adds a preference category to host rows for ethernet
interfaces.

Flag: com.android.settings.connectivity.ethernet_settings

Test: atest
SettingsRoboTests:
com.android.settings.network.NetworkProviderSettingsTest

Bug: 369889610

Change-Id: Idb37cbf17f06db2c9a217659affb35d9dcebadf3
This commit is contained in:
Nikhil Nayunigari
2025-01-21 19:50:40 +00:00
parent 17793e3c26
commit 25c5971e89
9 changed files with 202 additions and 34 deletions

View File

@@ -30,6 +30,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.LocationManager;
import android.net.EthernetManager;
import android.net.NetworkTemplate;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
@@ -69,7 +70,10 @@ import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.datausage.DataUsagePreference;
import com.android.settings.datausage.DataUsageUtils;
import com.android.settings.location.WifiScanningFragment;
import com.android.settings.network.ethernet.EthernetInterface;
import com.android.settings.network.ethernet.EthernetSwitchPreferenceController;
import com.android.settings.network.ethernet.EthernetTracker;
import com.android.settings.network.ethernet.EthernetTrackerImpl;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.wifi.AddNetworkFragment;
import com.android.settings.wifi.AddWifiNetworkPreference;
@@ -99,6 +103,7 @@ import com.android.wifitrackerlib.WifiEntry;
import com.android.wifitrackerlib.WifiEntry.ConnectCallback;
import com.android.wifitrackerlib.WifiPickerTracker;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
@@ -147,6 +152,7 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment
static final String PREF_KEY_DATA_USAGE = "non_carrier_data_usage";
private static final String PREF_KEY_RESET_INTERNET = "resetting_your_internet";
private static final String PREF_KEY_WIFI_STATUS_MESSAGE = "wifi_status_message_footer";
private static final String PREF_KEY_ETHERNET_INTERFACES = "ethernet_interfaces";
private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0;
@@ -252,6 +258,12 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment
@VisibleForTesting
MenuProvider mMenuProvider;
RestrictedSwitchPreference mEthernetSwitchPreference;
@VisibleForTesting
EthernetManager mEthernetManager;
@VisibleForTesting
EthernetTracker mEthernetTracker;
@VisibleForTesting
PreferenceCategory mEthernetPreferenceCategory;
/**
* Mobile networks list for provider model
@@ -390,6 +402,7 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment
.build(), SubscriptionManager.INVALID_SUBSCRIPTION_ID);
mResetInternetPreference = findPreference(PREF_KEY_RESET_INTERNET);
mEthernetSwitchPreference = findPreference(PREF_KEY_ETHERNET_TOGGLE);
mEthernetPreferenceCategory = findPreference(PREF_KEY_ETHERNET_INTERFACES);
if (mResetInternetPreference != null) {
mResetInternetPreference.setVisible(false);
}
@@ -482,6 +495,11 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment
mWifiPickerTracker = mWifiPickerTrackerHelper.getWifiPickerTracker();
}
mInternetUpdater = new InternetUpdater(getContext(), getSettingsLifecycle(), this);
if (com.android.settings.connectivity.Flags.ethernetSettings()) {
mEthernetManager = getContext().getSystemService(EthernetManager.class);
mEthernetTracker = EthernetTrackerImpl.getInstance(
getContext());
}
mSaveListener = new WifiManager.ActionListener() {
@Override
@@ -534,6 +552,9 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment
return;
}
mAirplaneModeEnabler.start();
if (com.android.settings.connectivity.Flags.ethernetSettings()) {
mEthernetTracker.registerInterfaceListener(this::onInterfaceListChanged);
}
}
private void restrictUi() {
@@ -571,6 +592,9 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment
getView().removeCallbacks(mUpdateWifiEntryPreferencesRunnable);
getView().removeCallbacks(mHideProgressBarRunnable);
mAirplaneModeEnabler.stop();
if (com.android.settings.connectivity.Flags.ethernetSettings()) {
mEthernetTracker.unregisterInterfaceListener(this::onInterfaceListChanged);
}
super.onStop();
}
@@ -644,6 +668,11 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment
}
}
/** Called when the list of ethernet interfaces has changed. */
public void onInterfaceListChanged(List<EthernetInterface> ethernetInterfaces) {
updateEthernetInterfaces(ethernetInterfaces);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
Preference preference = (Preference) view.getTag();
@@ -1081,6 +1110,28 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment
setAdditionalSettingsSummaries();
}
void updateEthernetInterfaces(Collection<EthernetInterface> interfaces) {
int index = 0;
mEthernetPreferenceCategory.removeAll();
if (interfaces.size() > 0) {
for (EthernetInterface ethernetInterface : interfaces) {
Preference pref = new Preference(getPrefContext());
pref.setSelectable(false);
pref.setOrder(index++);
pref.setKey(ethernetInterface.getId());
pref.setTitle(getContext().getString(R.string.ethernet_interface_title, index));
pref.setSummary(
(ethernetInterface.getInterfaceState() == EthernetManager.STATE_LINK_UP)
? getContext().getString(R.string.network_connected) :
getContext().getString(R.string.network_disconnected));
mEthernetPreferenceCategory.addPreference(pref);
}
mEthernetPreferenceCategory.setVisible(true);
} else {
mEthernetPreferenceCategory.setVisible(false);
}
}
@VisibleForTesting
PreferenceCategory getConnectedWifiPreferenceCategory() {
if (mInternetUpdater.getInternetType() == InternetUpdater.INTERNET_WIFI) {

View File

@@ -26,13 +26,12 @@ import android.net.IpConfiguration
import android.os.OutcomeReceiver
import android.util.Log
import androidx.core.content.ContextCompat
import java.util.concurrent.Executor
class EthernetInterface(private val context: Context, private val id: String) :
EthernetManager.InterfaceStateListener {
private val ethernetManager =
private val ethernetManager: EthernetManager? =
context.getSystemService(EthernetManager::class.java)
private val connectivityManager =
private val connectivityManager: ConnectivityManager? =
context.getSystemService(ConnectivityManager::class.java)
private val executor = ContextCompat.getMainExecutor(context)
@@ -43,6 +42,8 @@ class EthernetInterface(private val context: Context, private val id: String) :
fun getInterfaceState() = interfaceState
fun getId() = id
fun getConfiguration(): IpConfiguration {
return ipConfiguration
}
@@ -50,7 +51,7 @@ class EthernetInterface(private val context: Context, private val id: String) :
fun setConfiguration(ipConfiguration: IpConfiguration) {
val request =
EthernetNetworkUpdateRequest.Builder().setIpConfiguration(ipConfiguration).build()
ethernetManager.updateConfiguration(
ethernetManager?.updateConfiguration(
id,
request,
executor,

View File

@@ -33,13 +33,14 @@ import java.util.concurrent.Executor
class EthernetSwitchPreferenceController(context: Context, private val lifecycle: Lifecycle) :
AbstractPreferenceController(context),
LifecycleEventObserver,
EthernetInterfaceTracker.EthernetInterfaceTrackerListener {
EthernetTracker.EthernetInterfaceTrackerListener {
private val ethernetManager: EthernetManager? =
context.getSystemService(EthernetManager::class.java)
private var preference: RestrictedSwitchPreference? = null
private val executor = ContextCompat.getMainExecutor(context)
private val ethernetInterfaceTracker = EthernetInterfaceTracker.getInstance(context)
private val ethernetTracker =
EthernetTrackerImpl.getInstance(context)
init {
lifecycle.addObserver(this)
@@ -50,7 +51,7 @@ class EthernetSwitchPreferenceController(context: Context, private val lifecycle
}
override fun isAvailable(): Boolean {
return (Flags.ethernetSettings() && ethernetInterfaceTracker.availableInterfaces.size > 0)
return (Flags.ethernetSettings() && ethernetTracker.availableInterfaces.size > 0)
}
override fun displayPreference(screen: PreferenceScreen) {
@@ -63,12 +64,12 @@ class EthernetSwitchPreferenceController(context: Context, private val lifecycle
when (event) {
Lifecycle.Event.ON_START -> {
ethernetManager?.addEthernetStateListener(executor, this::onEthernetStateChanged)
ethernetInterfaceTracker.registerInterfaceListener(this)
ethernetTracker.registerInterfaceListener(this)
}
Lifecycle.Event.ON_STOP -> {
ethernetManager?.removeEthernetStateListener(this::onEthernetStateChanged)
ethernetInterfaceTracker.unregisterInterfaceListener(this)
ethernetTracker.unregisterInterfaceListener(this)
}
else -> {}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2025 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.network.ethernet
interface EthernetTracker {
interface EthernetInterfaceTrackerListener {
fun onInterfaceListChanged(ethernetInterfaces: List<EthernetInterface>)
}
val availableInterfaces: Collection<EthernetInterface>
interface EthernetInterfaceListListener {
fun onInterfaceListChanged()
}
fun getInterface(id: String): EthernetInterface?
fun registerInterfaceListener(listener: EthernetInterfaceTrackerListener)
fun unregisterInterfaceListener(listener: EthernetInterfaceTrackerListener)
}

View File

@@ -21,35 +21,40 @@ import android.net.EthernetManager
import android.net.IpConfiguration
import androidx.core.content.ContextCompat
class EthernetInterfaceTracker private constructor(private val context: Context) :
EthernetManager.InterfaceStateListener {
interface EthernetInterfaceTrackerListener {
fun onInterfaceListChanged(ethernetInterfaces: List<EthernetInterface>)
}
class EthernetTrackerImpl
private constructor(private val context: Context) :
EthernetManager.InterfaceStateListener, EthernetTracker {
private val TAG = "EthernetTracker"
private val ethernetManager: EthernetManager? =
context.applicationContext.getSystemService(EthernetManager::class.java)
private val TAG = "EthernetInterfaceTracker"
context.getSystemService(EthernetManager::class.java)
// Maps ethernet interface identifier to EthernetInterface object
private val ethernetInterfaces = mutableMapOf<String, EthernetInterface>()
private val interfaceListeners = mutableListOf<EthernetInterfaceTrackerListener>()
private val interfaceListeners =
mutableListOf<EthernetTracker.EthernetInterfaceTrackerListener>()
fun getInterface(id: String): EthernetInterface? {
override fun getInterface(id: String): EthernetInterface? {
return ethernetInterfaces.get(id)
}
val availableInterfaces: Collection<EthernetInterface>
override val availableInterfaces: Collection<EthernetInterface>
get() = ethernetInterfaces.values
fun registerInterfaceListener(listener: EthernetInterfaceTrackerListener) {
override fun registerInterfaceListener(
listener: EthernetTracker.EthernetInterfaceTrackerListener
) {
if (interfaceListeners.isEmpty()) {
ethernetManager?.addInterfaceStateListener(ContextCompat.getMainExecutor(context), this)
}
interfaceListeners.add(listener)
listener.onInterfaceListChanged(ethernetInterfaces.values.toList())
}
fun unregisterInterfaceListener(listener: EthernetInterfaceTrackerListener) {
override fun unregisterInterfaceListener(
listener: EthernetTracker.EthernetInterfaceTrackerListener
) {
interfaceListeners.remove(listener)
if (interfaceListeners.isEmpty()) {
ethernetManager?.removeInterfaceStateListener(this)
@@ -73,12 +78,16 @@ class EthernetInterfaceTracker private constructor(private val context: Context)
}
companion object {
@Volatile private var INSTANCE: EthernetInterfaceTracker? = null
@Volatile private var INSTANCE: EthernetTrackerImpl? = null
fun getInstance(context: Context): EthernetInterfaceTracker {
@JvmStatic
fun getInstance(
context: Context
): EthernetTrackerImpl {
return INSTANCE
?: synchronized(this) {
val instance = EthernetInterfaceTracker(context.applicationContext)
val instance =
EthernetTrackerImpl(context.applicationContext)
INSTANCE = instance
instance
}