Merge "Edits ethernet interface details settings subpage with more info" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
989c4cf698
@@ -3912,6 +3912,18 @@
|
||||
<!-- Label for bluetooth tether checkbox [CHAR LIMIT=25]-->
|
||||
<string name="bluetooth_tether_checkbox_text">Bluetooth tethering</string>
|
||||
|
||||
<!-- Ethernet settings-->
|
||||
<!-- Label for ethernet IP address [CHAR LIMIT=NONE]-->
|
||||
<string name="ethernet_ip_address">IP address</string>
|
||||
<!-- Label for ethernet MAC address [CHAR LIMIT=NONE]-->
|
||||
<string name="ethernet_mac_address_title">MAC address</string>
|
||||
<!-- Label for ethernet transfer speed [CHAR LIMIT=NONE]-->
|
||||
<string name="tx_ethernet_speed">Transit link speed</string>
|
||||
<!-- Label for ethernet receive speed [CHAR LIMIT=NONE]-->
|
||||
<string name="rx_ethernet_speed">Receive link speed</string>
|
||||
<!-- Label for ethernet network usage [CHAR LIMIT=NONE]-->
|
||||
<string name="ethernet_network_usage">Network usage</string>
|
||||
|
||||
<!-- Ethernet Tethering settings-->
|
||||
<!-- Label for ethernet tether checkbox [CHAR LIMIT=NONE]-->
|
||||
<string name="ethernet_tether_checkbox_text">Ethernet tethering</string>
|
||||
|
@@ -24,4 +24,36 @@
|
||||
android:selectable="false"
|
||||
android:order="-10000"/>
|
||||
|
||||
<ListPreference
|
||||
android:key="metered"
|
||||
android:icon="@drawable/ic_attach_money_black_24dp"
|
||||
android:title="@string/wifi_metered_title"
|
||||
android:entries="@array/wifi_metered_entries"
|
||||
android:entryValues="@array/wifi_metered_values"/>
|
||||
|
||||
<!-- Network Details -->
|
||||
<PreferenceCategory
|
||||
android:key="ip_details_category">
|
||||
<Preference
|
||||
android:key="ethernet_ip_address"
|
||||
android:title="@string/ethernet_ip_address"
|
||||
android:selectable="false"
|
||||
settings:enableCopying="true"/>
|
||||
<Preference
|
||||
android:key="ethernet_mac_address"
|
||||
android:title="@string/ethernet_mac_address_title"
|
||||
android:selectable="false"
|
||||
settings:enableCopying="true"/>
|
||||
<Preference
|
||||
android:key="ethernet_tx_link_speed"
|
||||
android:title="@string/tx_ethernet_speed"
|
||||
android:selectable="false"
|
||||
settings:enableCopying="true"/>
|
||||
<Preference
|
||||
android:key="ethernet_rx_link_speed"
|
||||
android:title="@string/rx_ethernet_speed"
|
||||
android:selectable="false"
|
||||
settings:enableCopying="true"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
@@ -18,34 +18,68 @@ package com.android.settings.network.ethernet
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.ConnectivityManager.NetworkCallback
|
||||
import android.net.EthernetManager
|
||||
import android.net.EthernetManager.STATE_ABSENT
|
||||
import android.net.EthernetNetworkManagementException
|
||||
import android.net.EthernetNetworkUpdateRequest
|
||||
import android.net.IpConfiguration
|
||||
import android.net.LinkProperties
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import android.os.OutcomeReceiver
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.common.annotations.VisibleForTesting
|
||||
|
||||
class EthernetInterface(private val context: Context, private val id: String) :
|
||||
EthernetManager.InterfaceStateListener {
|
||||
interface EthernetInterfaceStateListener {
|
||||
fun interfaceUpdated()
|
||||
}
|
||||
|
||||
private val ethernetManager: EthernetManager? =
|
||||
context.getSystemService(EthernetManager::class.java)
|
||||
private val connectivityManager: ConnectivityManager? =
|
||||
context.getSystemService(ConnectivityManager::class.java)
|
||||
private val executor = ContextCompat.getMainExecutor(context)
|
||||
private val interfaceListeners = mutableListOf<EthernetInterfaceStateListener>()
|
||||
|
||||
private val TAG = "EthernetInterface"
|
||||
|
||||
private val networkRequest: NetworkRequest =
|
||||
NetworkRequest.Builder()
|
||||
.clearCapabilities()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.build()
|
||||
|
||||
private var interfaceState = STATE_ABSENT
|
||||
private var ipConfiguration = IpConfiguration()
|
||||
private var linkProperties = LinkProperties()
|
||||
|
||||
fun getInterfaceState() = interfaceState
|
||||
|
||||
fun getId() = id
|
||||
|
||||
fun getConfiguration(): IpConfiguration {
|
||||
return ipConfiguration
|
||||
fun getConfiguration() = ipConfiguration
|
||||
|
||||
fun getLinkProperties() = linkProperties
|
||||
|
||||
fun registerListener(listener: EthernetInterfaceStateListener) {
|
||||
if (interfaceListeners.isEmpty()) {
|
||||
ethernetManager?.addInterfaceStateListener(ContextCompat.getMainExecutor(context), this)
|
||||
connectivityManager?.registerNetworkCallback(networkRequest, networkCallback)
|
||||
}
|
||||
interfaceListeners.add(listener)
|
||||
}
|
||||
|
||||
fun unregisterListener(listener: EthernetInterfaceStateListener) {
|
||||
interfaceListeners.remove(listener)
|
||||
if (interfaceListeners.isEmpty()) {
|
||||
connectivityManager?.unregisterNetworkCallback(networkCallback)
|
||||
ethernetManager?.removeInterfaceStateListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun setConfiguration(ipConfiguration: IpConfiguration) {
|
||||
@@ -67,10 +101,28 @@ class EthernetInterface(private val context: Context, private val id: String) :
|
||||
)
|
||||
}
|
||||
|
||||
private fun notifyListeners() {
|
||||
for (listener in interfaceListeners) {
|
||||
listener.interfaceUpdated()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInterfaceStateChanged(id: String, state: Int, role: Int, cfg: IpConfiguration?) {
|
||||
if (id == this.id) {
|
||||
ipConfiguration = cfg ?: IpConfiguration()
|
||||
interfaceState = state
|
||||
notifyListeners()
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
val networkCallback =
|
||||
object : NetworkCallback() {
|
||||
override fun onLinkPropertiesChanged(network: Network, lp: LinkProperties) {
|
||||
if (lp.getInterfaceName().equals(id)) {
|
||||
linkProperties = lp
|
||||
notifyListeners()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,14 @@ package com.android.settings.network.ethernet
|
||||
|
||||
import android.content.Context
|
||||
import android.net.EthernetManager
|
||||
import android.net.IpConfiguration
|
||||
import android.net.LinkProperties
|
||||
import android.net.StaticIpConfiguration
|
||||
import android.widget.ImageView
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.android.settings.R
|
||||
@@ -30,13 +37,25 @@ class EthernetInterfaceDetailsController(
|
||||
context: Context,
|
||||
private val fragment: PreferenceFragmentCompat,
|
||||
private val preferenceId: String,
|
||||
) : AbstractPreferenceController(context) {
|
||||
private val lifecycle: Lifecycle,
|
||||
) :
|
||||
AbstractPreferenceController(context),
|
||||
EthernetInterface.EthernetInterfaceStateListener,
|
||||
LifecycleEventObserver {
|
||||
private val KEY_HEADER = "ethernet_details"
|
||||
|
||||
private val ethernetManager = context.getSystemService(EthernetManager::class.java)
|
||||
private val ethernetInterface =
|
||||
EthernetTrackerImpl.getInstance(context).getInterface(preferenceId)
|
||||
|
||||
private lateinit var entityHeaderController: EntityHeaderController
|
||||
|
||||
private var ipAddressPref: Preference? = null
|
||||
|
||||
init {
|
||||
lifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
override fun isAvailable(): Boolean {
|
||||
return true
|
||||
}
|
||||
@@ -45,10 +64,24 @@ class EthernetInterfaceDetailsController(
|
||||
return KEY_HEADER
|
||||
}
|
||||
|
||||
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_START -> {
|
||||
ethernetInterface?.registerListener(this)
|
||||
}
|
||||
|
||||
Lifecycle.Event.ON_STOP -> {
|
||||
ethernetInterface?.unregisterListener(this)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
override fun displayPreference(screen: PreferenceScreen) {
|
||||
val headerPref: LayoutPreference? = screen.findPreference(KEY_HEADER)
|
||||
|
||||
val mEntityHeaderController =
|
||||
entityHeaderController =
|
||||
EntityHeaderController.newInstance(
|
||||
fragment.getActivity(),
|
||||
fragment,
|
||||
@@ -59,7 +92,8 @@ class EthernetInterfaceDetailsController(
|
||||
|
||||
iconView?.setScaleType(ImageView.ScaleType.CENTER_INSIDE)
|
||||
|
||||
mEntityHeaderController
|
||||
if (entityHeaderController != null) {
|
||||
entityHeaderController
|
||||
.setLabel("Ethernet")
|
||||
.setSummary(
|
||||
if (ethernetInterface?.getInterfaceState() == EthernetManager.STATE_LINK_UP) {
|
||||
@@ -72,4 +106,35 @@ class EthernetInterfaceDetailsController(
|
||||
.setIcon(mContext.getDrawable(R.drawable.ic_settings_ethernet))
|
||||
.done(true /* rebind */)
|
||||
}
|
||||
|
||||
ipAddressPref = screen.findPreference<Preference>("ethernet_ip_address")
|
||||
|
||||
if (ethernetInterface?.getInterfaceState() == EthernetManager.STATE_LINK_UP) {
|
||||
initializeIpDetails()
|
||||
}
|
||||
}
|
||||
|
||||
override fun interfaceUpdated() {
|
||||
entityHeaderController?.setSummary(
|
||||
if (ethernetInterface?.getInterfaceState() == EthernetManager.STATE_LINK_UP) {
|
||||
mContext.getString(R.string.network_connected)
|
||||
} else {
|
||||
mContext.getString(R.string.network_disconnected)
|
||||
}
|
||||
)
|
||||
initializeIpDetails()
|
||||
}
|
||||
|
||||
private fun initializeIpDetails() {
|
||||
val ipConfiguration: IpConfiguration? = ethernetInterface?.getConfiguration()
|
||||
val linkProperties: LinkProperties? = ethernetInterface?.getLinkProperties()
|
||||
|
||||
if (ipConfiguration?.getIpAssignment() == IpConfiguration.IpAssignment.STATIC) {
|
||||
val staticIp: StaticIpConfiguration? = ipConfiguration?.getStaticIpConfiguration()
|
||||
ipAddressPref?.setSummary(staticIp?.getIpAddress().toString())
|
||||
} else {
|
||||
val addresses = linkProperties?.getAddresses()
|
||||
ipAddressPref?.setSummary(addresses?.first().toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -50,6 +50,13 @@ class EthernetInterfaceDetailsFragment : DashboardFragment() {
|
||||
override public fun createPreferenceControllers(
|
||||
context: Context
|
||||
): List<AbstractPreferenceController> {
|
||||
return listOf(EthernetInterfaceDetailsController(context, this, preferenceId ?: ""))
|
||||
return listOf(
|
||||
EthernetInterfaceDetailsController(
|
||||
context,
|
||||
this,
|
||||
preferenceId ?: "",
|
||||
getSettingsLifecycle(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -18,22 +18,30 @@ package com.android.settings.network.ethernet
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.mock
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class EthernetInterfaceDetailsControllerTest {
|
||||
private val ethernetInterfaceDetailsFragment = EthernetInterfaceDetailsFragment()
|
||||
private val lifecycle = mock<Lifecycle>()
|
||||
|
||||
private val context: Context =
|
||||
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {}
|
||||
|
||||
private val ethernetInterfaceDetailsController =
|
||||
EthernetInterfaceDetailsController(context, ethernetInterfaceDetailsFragment, "eth0")
|
||||
EthernetInterfaceDetailsController(
|
||||
context,
|
||||
ethernetInterfaceDetailsFragment,
|
||||
"eth0",
|
||||
lifecycle,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun isAvailable_ShouldReturnTrue() {
|
||||
|
@@ -18,14 +18,19 @@ package com.android.settings.network.ethernet
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.net.ConnectivityManager
|
||||
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 android.net.LinkProperties
|
||||
import android.net.Network
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.mock
|
||||
@@ -34,12 +39,15 @@ import org.mockito.kotlin.mock
|
||||
class EthernetInterfaceTest {
|
||||
|
||||
private val mockEthernetManager = mock<EthernetManager>()
|
||||
private val mockConnectivityManager = mock<ConnectivityManager>()
|
||||
private val mockNetwork = mock<Network>()
|
||||
|
||||
private val context: Context =
|
||||
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
|
||||
override fun getSystemService(name: String): Any? =
|
||||
when (name) {
|
||||
Context.ETHERNET_SERVICE -> mockEthernetManager
|
||||
Context.CONNECTIVITY_SERVICE -> mockConnectivityManager
|
||||
else -> super.getSystemService(name)
|
||||
}
|
||||
}
|
||||
@@ -85,4 +93,27 @@ class EthernetInterfaceTest {
|
||||
IpConfiguration.IpAssignment.UNASSIGNED,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun linkPropertiesChanged_shouldUpdate() {
|
||||
val linkProperties = LinkProperties()
|
||||
linkProperties.setInterfaceName("eth0")
|
||||
linkProperties.setUsePrivateDns(true)
|
||||
|
||||
ethernetInterface.networkCallback.onLinkPropertiesChanged(mockNetwork, linkProperties)
|
||||
|
||||
assertEquals(ethernetInterface.getLinkProperties().getInterfaceName(), "eth0")
|
||||
assertTrue(ethernetInterface.getLinkProperties().isPrivateDnsActive())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun linkPropertiesChanged_iddoesnotmatch_shouldNotUpdate() {
|
||||
val linkProperties = LinkProperties()
|
||||
linkProperties.setInterfaceName("eth1")
|
||||
linkProperties.setUsePrivateDns(true)
|
||||
|
||||
ethernetInterface.networkCallback.onLinkPropertiesChanged(mockNetwork, linkProperties)
|
||||
|
||||
assertFalse(ethernetInterface.getLinkProperties().isPrivateDnsActive())
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user