Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d662c5b authored by Nikhil Nayunigari's avatar Nikhil Nayunigari
Browse files

Adding EthernetInterfaceTracker to support EthernetSettings

This class is part of the middleware and will be used to be notified
when an EthernetInterface is added or removed.

Flag: com.android.settings.connectivity.ethernet_settings

Test: atest
SettingsRoboTests: com.android.settings.network.EthernetInterfaceTrackerTest
Change-Id: If3a1f4d7a96b301cd47ffbea55864bcc780cd1e0
parent 6d2152fb
Loading
Loading
Loading
Loading
+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()
            }
        }
    }
}
+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)
    }
}