Loading src/com/android/settings/network/ethernet/EthernetInterface.kt 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.net.ConnectivityManager import android.net.EthernetManager import android.net.EthernetManager.STATE_ABSENT import android.net.EthernetNetworkManagementException import android.net.EthernetNetworkUpdateRequest 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 = context.getSystemService(EthernetManager::class.java) private val connectivityManager = context.getSystemService(ConnectivityManager::class.java) private val executor = ContextCompat.getMainExecutor(context) private val TAG = "EthernetInterface" private var interfaceState = STATE_ABSENT private var ipConfiguration = IpConfiguration() fun getInterfaceState() = interfaceState fun getConfiguration(): IpConfiguration { return ipConfiguration } fun setConfiguration(ipConfiguration: IpConfiguration) { val request = EthernetNetworkUpdateRequest.Builder().setIpConfiguration(ipConfiguration).build() ethernetManager.updateConfiguration( id, request, executor, object : OutcomeReceiver<String, EthernetNetworkManagementException> { override fun onError(e: EthernetNetworkManagementException) { Log.e(TAG, "Failed to updateConfiguration: ", e) } override fun onResult(id: String) { Log.d(TAG, "Successfully updated configuration: " + id) } }, ) } override fun onInterfaceStateChanged(id: String, state: Int, role: Int, cfg: IpConfiguration?) { if (id == this.id) { ipConfiguration = cfg ?: IpConfiguration() interfaceState = state } } } src/com/android/settings/network/ethernet/EthernetInterfaceTracker.kt 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.net.EthernetManager import android.net.IpConfiguration import androidx.core.content.ContextCompat import java.util.concurrent.Executor class EthernetInterfaceTracker(private val context: Context) : EthernetManager.InterfaceStateListener { interface EthernetInterfaceListListener { fun onInterfaceListChanged() } private val ethernetManager = context.getSystemService(Context.ETHERNET_SERVICE) as EthernetManager private val TAG = "EthernetInterfaceTracker" // Maps ethernet interface identifier to EthernetInterface object private val ethernetInterfaces = mutableMapOf<String, EthernetInterface>() private val interfaceListeners = mutableListOf<EthernetInterfaceListListener>() private val mExecutor = ContextCompat.getMainExecutor(context) init { ethernetManager.addInterfaceStateListener(mExecutor, this) } fun getInterface(id: String): EthernetInterface? { return ethernetInterfaces.get(id) } fun getAvailableInterfaces(): Collection<EthernetInterface> { return ethernetInterfaces.values } fun registerInterfaceListener(listener: EthernetInterfaceListListener) { interfaceListeners.add(listener) } fun unregisterInterfaceListener(listener: EthernetInterfaceListListener) { interfaceListeners.remove(listener) } override fun onInterfaceStateChanged(id: String, state: Int, role: Int, cfg: IpConfiguration?) { var interfacesChanged = false if (!ethernetInterfaces.contains(id) && state != EthernetManager.STATE_ABSENT) { ethernetInterfaces.put(id, EthernetInterface(context, id)) interfacesChanged = true } else if (ethernetInterfaces.contains(id) && state == EthernetManager.STATE_ABSENT) { ethernetInterfaces.remove(id) interfacesChanged = true } if (interfacesChanged) { for (listener in interfaceListeners) { listener.onInterfaceListChanged() } } } } tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceTest.kt 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.content.ContextWrapper import android.net.EthernetManager import android.net.EthernetManager.STATE_ABSENT import android.net.EthernetManager.STATE_LINK_DOWN import android.net.EthernetManager.STATE_LINK_UP import android.net.IpConfiguration import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @RunWith(AndroidJUnit4::class) class EthernetInterfaceTest { private val mockEthernetManager = mock<EthernetManager>() private val context: Context = object : ContextWrapper(ApplicationProvider.getApplicationContext()) { override fun getSystemService(name: String): Any? = when (name) { Context.ETHERNET_SERVICE -> mockEthernetManager else -> super.getSystemService(name) } } private val ethernetInterface = EthernetInterface(context, "eth0") @Test fun getInterfaceState_shouldReturnDefaultState() { assertEquals(ethernetInterface.getInterfaceState(), STATE_ABSENT) } @Test fun getConfiguration_shouldReturnDefaultIpConfig() { val ipConfiguration: IpConfiguration = ethernetInterface.getConfiguration() assertEquals(ipConfiguration.getIpAssignment(), IpConfiguration.IpAssignment.UNASSIGNED) } @Test fun interfaceStateChanged_shouldUpdateState() { val testConfig = IpConfiguration() testConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC) ethernetInterface.onInterfaceStateChanged("eth0", STATE_LINK_UP, 0, testConfig) assertEquals(ethernetInterface.getInterfaceState(), STATE_LINK_UP) assertEquals( ethernetInterface.getConfiguration().getIpAssignment(), IpConfiguration.IpAssignment.STATIC, ) } @Test fun interfaceStateChanged_iddoesnotmatch_shouldNotUpdateState() { val testConfig = IpConfiguration() testConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC) ethernetInterface.onInterfaceStateChanged("eth1", STATE_LINK_DOWN, 0, testConfig) assertEquals(ethernetInterface.getInterfaceState(), STATE_ABSENT) assertEquals( ethernetInterface.getConfiguration().getIpAssignment(), IpConfiguration.IpAssignment.UNASSIGNED, ) } } tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceTrackerTest.kt 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.content.ContextWrapper import android.net.EthernetManager import android.net.IpConfiguration import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @RunWith(AndroidJUnit4::class) class EthernetInterfaceTrackerTest { private val mockEthernetManager = mock<EthernetManager>() private val context: Context = object : ContextWrapper(ApplicationProvider.getApplicationContext()) { override fun getSystemService(name: String): Any? = when (name) { Context.ETHERNET_SERVICE -> mockEthernetManager else -> super.getSystemService(name) } } private val ethernetInterfaceTracker = EthernetInterfaceTracker(context) @Test fun getInterface_shouldReturnEmpty() { assertNull(ethernetInterfaceTracker.getInterface("id0")) } @Test fun getAvailableInterfaces_shouldReturnEmpty() { assertEquals(ethernetInterfaceTracker.getAvailableInterfaces().size, 0) } @Test fun interfacesChanged_shouldUpdateInterfaces() { ethernetInterfaceTracker.onInterfaceStateChanged( "id0", EthernetManager.STATE_LINK_DOWN, EthernetManager.ROLE_NONE, IpConfiguration(), ) assertNotNull(ethernetInterfaceTracker.getInterface("id0")) assertEquals(ethernetInterfaceTracker.getAvailableInterfaces().size, 1) ethernetInterfaceTracker.onInterfaceStateChanged( "id0", EthernetManager.STATE_ABSENT, EthernetManager.ROLE_NONE, IpConfiguration(), ) assertNull(ethernetInterfaceTracker.getInterface("id0")) assertEquals(ethernetInterfaceTracker.getAvailableInterfaces().size, 0) } } Loading
src/com/android/settings/network/ethernet/EthernetInterface.kt 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.net.ConnectivityManager import android.net.EthernetManager import android.net.EthernetManager.STATE_ABSENT import android.net.EthernetNetworkManagementException import android.net.EthernetNetworkUpdateRequest 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 = context.getSystemService(EthernetManager::class.java) private val connectivityManager = context.getSystemService(ConnectivityManager::class.java) private val executor = ContextCompat.getMainExecutor(context) private val TAG = "EthernetInterface" private var interfaceState = STATE_ABSENT private var ipConfiguration = IpConfiguration() fun getInterfaceState() = interfaceState fun getConfiguration(): IpConfiguration { return ipConfiguration } fun setConfiguration(ipConfiguration: IpConfiguration) { val request = EthernetNetworkUpdateRequest.Builder().setIpConfiguration(ipConfiguration).build() ethernetManager.updateConfiguration( id, request, executor, object : OutcomeReceiver<String, EthernetNetworkManagementException> { override fun onError(e: EthernetNetworkManagementException) { Log.e(TAG, "Failed to updateConfiguration: ", e) } override fun onResult(id: String) { Log.d(TAG, "Successfully updated configuration: " + id) } }, ) } override fun onInterfaceStateChanged(id: String, state: Int, role: Int, cfg: IpConfiguration?) { if (id == this.id) { ipConfiguration = cfg ?: IpConfiguration() interfaceState = state } } }
src/com/android/settings/network/ethernet/EthernetInterfaceTracker.kt 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.net.EthernetManager import android.net.IpConfiguration import androidx.core.content.ContextCompat import java.util.concurrent.Executor class EthernetInterfaceTracker(private val context: Context) : EthernetManager.InterfaceStateListener { interface EthernetInterfaceListListener { fun onInterfaceListChanged() } private val ethernetManager = context.getSystemService(Context.ETHERNET_SERVICE) as EthernetManager private val TAG = "EthernetInterfaceTracker" // Maps ethernet interface identifier to EthernetInterface object private val ethernetInterfaces = mutableMapOf<String, EthernetInterface>() private val interfaceListeners = mutableListOf<EthernetInterfaceListListener>() private val mExecutor = ContextCompat.getMainExecutor(context) init { ethernetManager.addInterfaceStateListener(mExecutor, this) } fun getInterface(id: String): EthernetInterface? { return ethernetInterfaces.get(id) } fun getAvailableInterfaces(): Collection<EthernetInterface> { return ethernetInterfaces.values } fun registerInterfaceListener(listener: EthernetInterfaceListListener) { interfaceListeners.add(listener) } fun unregisterInterfaceListener(listener: EthernetInterfaceListListener) { interfaceListeners.remove(listener) } override fun onInterfaceStateChanged(id: String, state: Int, role: Int, cfg: IpConfiguration?) { var interfacesChanged = false if (!ethernetInterfaces.contains(id) && state != EthernetManager.STATE_ABSENT) { ethernetInterfaces.put(id, EthernetInterface(context, id)) interfacesChanged = true } else if (ethernetInterfaces.contains(id) && state == EthernetManager.STATE_ABSENT) { ethernetInterfaces.remove(id) interfacesChanged = true } if (interfacesChanged) { for (listener in interfaceListeners) { listener.onInterfaceListChanged() } } } }
tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceTest.kt 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.content.ContextWrapper import android.net.EthernetManager import android.net.EthernetManager.STATE_ABSENT import android.net.EthernetManager.STATE_LINK_DOWN import android.net.EthernetManager.STATE_LINK_UP import android.net.IpConfiguration import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @RunWith(AndroidJUnit4::class) class EthernetInterfaceTest { private val mockEthernetManager = mock<EthernetManager>() private val context: Context = object : ContextWrapper(ApplicationProvider.getApplicationContext()) { override fun getSystemService(name: String): Any? = when (name) { Context.ETHERNET_SERVICE -> mockEthernetManager else -> super.getSystemService(name) } } private val ethernetInterface = EthernetInterface(context, "eth0") @Test fun getInterfaceState_shouldReturnDefaultState() { assertEquals(ethernetInterface.getInterfaceState(), STATE_ABSENT) } @Test fun getConfiguration_shouldReturnDefaultIpConfig() { val ipConfiguration: IpConfiguration = ethernetInterface.getConfiguration() assertEquals(ipConfiguration.getIpAssignment(), IpConfiguration.IpAssignment.UNASSIGNED) } @Test fun interfaceStateChanged_shouldUpdateState() { val testConfig = IpConfiguration() testConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC) ethernetInterface.onInterfaceStateChanged("eth0", STATE_LINK_UP, 0, testConfig) assertEquals(ethernetInterface.getInterfaceState(), STATE_LINK_UP) assertEquals( ethernetInterface.getConfiguration().getIpAssignment(), IpConfiguration.IpAssignment.STATIC, ) } @Test fun interfaceStateChanged_iddoesnotmatch_shouldNotUpdateState() { val testConfig = IpConfiguration() testConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC) ethernetInterface.onInterfaceStateChanged("eth1", STATE_LINK_DOWN, 0, testConfig) assertEquals(ethernetInterface.getInterfaceState(), STATE_ABSENT) assertEquals( ethernetInterface.getConfiguration().getIpAssignment(), IpConfiguration.IpAssignment.UNASSIGNED, ) } }
tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceTrackerTest.kt 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.content.ContextWrapper import android.net.EthernetManager import android.net.IpConfiguration import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @RunWith(AndroidJUnit4::class) class EthernetInterfaceTrackerTest { private val mockEthernetManager = mock<EthernetManager>() private val context: Context = object : ContextWrapper(ApplicationProvider.getApplicationContext()) { override fun getSystemService(name: String): Any? = when (name) { Context.ETHERNET_SERVICE -> mockEthernetManager else -> super.getSystemService(name) } } private val ethernetInterfaceTracker = EthernetInterfaceTracker(context) @Test fun getInterface_shouldReturnEmpty() { assertNull(ethernetInterfaceTracker.getInterface("id0")) } @Test fun getAvailableInterfaces_shouldReturnEmpty() { assertEquals(ethernetInterfaceTracker.getAvailableInterfaces().size, 0) } @Test fun interfacesChanged_shouldUpdateInterfaces() { ethernetInterfaceTracker.onInterfaceStateChanged( "id0", EthernetManager.STATE_LINK_DOWN, EthernetManager.ROLE_NONE, IpConfiguration(), ) assertNotNull(ethernetInterfaceTracker.getInterface("id0")) assertEquals(ethernetInterfaceTracker.getAvailableInterfaces().size, 1) ethernetInterfaceTracker.onInterfaceStateChanged( "id0", EthernetManager.STATE_ABSENT, EthernetManager.ROLE_NONE, IpConfiguration(), ) assertNull(ethernetInterfaceTracker.getInterface("id0")) assertEquals(ethernetInterfaceTracker.getAvailableInterfaces().size, 0) } }