Merge changes from topic "Ethernet Settings" into main
* changes: Adding EthernetInterfaceTracker to support EthernetSettings Adding middleware to support EthernetSettings
This commit is contained in:
committed by
Android (Google) Code Review
commit
3db5f484ce
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user