From 487a4774d149115171cdf7707dc3745f16e9b2de Mon Sep 17 00:00:00 2001 From: Nikhil Nayunigari Date: Mon, 3 Feb 2025 05:10:55 +0000 Subject: [PATCH] Add ethernet interface details settings subpage Adds a click listener to the ethernet interface row and displays a settings subpage with interface connection status. Flag: com.android.settings.connectivity.ethernet_settings Test: atest SettingsRoboTests: com.android.settings.network.NetworkProviderSettingsTest Change-Id: Id64ce3657b47dd4ca70d425dd3d13227c8468d2c --- res/xml/ethernet_interface_details.xml | 27 +++++++ .../network/NetworkProviderSettings.java | 20 ++++- .../EthernetInterfaceDetailsController.kt | 75 +++++++++++++++++++ .../EthernetInterfaceDetailsFragment.kt | 55 ++++++++++++++ .../EthernetInterfaceDetailsControllerTest.kt | 47 ++++++++++++ .../EthernetInterfaceDetailsFragmentTest.kt | 69 +++++++++++++++++ 6 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 res/xml/ethernet_interface_details.xml create mode 100644 src/com/android/settings/network/ethernet/EthernetInterfaceDetailsController.kt create mode 100644 src/com/android/settings/network/ethernet/EthernetInterfaceDetailsFragment.kt create mode 100644 tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsControllerTest.kt create mode 100644 tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsFragmentTest.kt diff --git a/res/xml/ethernet_interface_details.xml b/res/xml/ethernet_interface_details.xml new file mode 100644 index 00000000000..f2d106f4d2a --- /dev/null +++ b/res/xml/ethernet_interface_details.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java index f0f947023b1..3f9d4955a37 100644 --- a/src/com/android/settings/network/NetworkProviderSettings.java +++ b/src/com/android/settings/network/NetworkProviderSettings.java @@ -71,6 +71,7 @@ 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.EthernetInterfaceDetailsFragment; import com.android.settings.network.ethernet.EthernetSwitchPreferenceController; import com.android.settings.network.ethernet.EthernetTracker; import com.android.settings.network.ethernet.EthernetTrackerImpl; @@ -1116,7 +1117,6 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment 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)); @@ -1124,6 +1124,10 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment (ethernetInterface.getInterfaceState() == EthernetManager.STATE_LINK_UP) ? getContext().getString(R.string.network_connected) : getContext().getString(R.string.network_disconnected)); + pref.setOnPreferenceClickListener(preference -> { + launchEthernetInterfaceDetailsFragment(preference); + return true; + }); mEthernetPreferenceCategory.addPreference(pref); } mEthernetPreferenceCategory.setVisible(true); @@ -1173,6 +1177,20 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment .launch(); } + @VisibleForTesting + void launchEthernetInterfaceDetailsFragment(Preference pref) { + final Context context = requireContext(); + + final Bundle bundle = new Bundle(); + bundle.putString("EthernetInterfaceKey", pref.getKey()); + + new SubSettingLauncher(context) + .setDestination(EthernetInterfaceDetailsFragment.class.getName()) + .setArguments(bundle) + .setSourceMetricsCategory(getMetricsCategory()) + .launch(); + } + @VisibleForTesting LongPressWifiEntryPreference createLongPressWifiEntryPreference(WifiEntry wifiEntry) { return new LongPressWifiEntryPreference(getPrefContext(), wifiEntry, this); diff --git a/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsController.kt b/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsController.kt new file mode 100644 index 00000000000..cb3ad1db8ae --- /dev/null +++ b/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsController.kt @@ -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.widget.ImageView +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceScreen +import com.android.settings.R +import com.android.settings.widget.EntityHeaderController +import com.android.settingslib.core.AbstractPreferenceController +import com.android.settingslib.widget.LayoutPreference + +class EthernetInterfaceDetailsController( + context: Context, + private val fragment: PreferenceFragmentCompat, + private val preferenceId: String, +) : AbstractPreferenceController(context) { + private val KEY_HEADER = "ethernet_details" + + private val ethernetManager = context.getSystemService(EthernetManager::class.java) + private val ethernetInterface = + EthernetTrackerImpl.getInstance(context).getInterface(preferenceId) + + override fun isAvailable(): Boolean { + return true + } + + override fun getPreferenceKey(): String? { + return KEY_HEADER + } + + override fun displayPreference(screen: PreferenceScreen) { + val headerPref: LayoutPreference? = screen.findPreference(KEY_HEADER) + + val mEntityHeaderController = + EntityHeaderController.newInstance( + fragment.getActivity(), + fragment, + headerPref?.findViewById(R.id.entity_header), + ) + + val iconView: ImageView? = headerPref?.findViewById(R.id.entity_header_icon) + + iconView?.setScaleType(ImageView.ScaleType.CENTER_INSIDE) + + mEntityHeaderController + .setLabel("Ethernet") + .setSummary( + if (ethernetInterface?.getInterfaceState() == EthernetManager.STATE_LINK_UP) { + mContext.getString(R.string.network_connected) + } else { + mContext.getString(R.string.network_disconnected) + } + ) + .setSecondSummary("") + .setIcon(mContext.getDrawable(R.drawable.ic_settings_ethernet)) + .done(true /* rebind */) + } +} diff --git a/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsFragment.kt b/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsFragment.kt new file mode 100644 index 00000000000..a6cf90fed6b --- /dev/null +++ b/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsFragment.kt @@ -0,0 +1,55 @@ +/* + * 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.app.settings.SettingsEnums +import android.content.Context +import android.os.Bundle +import androidx.annotation.VisibleForTesting +import com.android.settings.R +import com.android.settings.dashboard.DashboardFragment +import com.android.settingslib.core.AbstractPreferenceController + +class EthernetInterfaceDetailsFragment : DashboardFragment() { + private val TAG = "EthernetInterfaceDetailsFragment" + private val ETHERNET_INTERFACE_KEY = "EthernetInterfaceKey" + private var preferenceId: String? = null + + override fun onCreate(bundle: Bundle?) { + super.onCreate(bundle) + preferenceId = bundle?.getString(ETHERNET_INTERFACE_KEY) + } + + override public fun getPreferenceScreenResId(): Int { + return R.xml.ethernet_interface_details + } + + @VisibleForTesting + override fun getMetricsCategory(): Int { + return SettingsEnums.ETHERNET_SETTINGS + } + + override public fun getLogTag(): String { + return TAG + } + + override public fun createPreferenceControllers( + context: Context + ): List { + return listOf(EthernetInterfaceDetailsController(context, this, preferenceId ?: "")) + } +} diff --git a/tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsControllerTest.kt b/tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsControllerTest.kt new file mode 100644 index 00000000000..fb8e4762bbc --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsControllerTest.kt @@ -0,0 +1,47 @@ +/* + * 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 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 + +@RunWith(AndroidJUnit4::class) +class EthernetInterfaceDetailsControllerTest { + private val ethernetInterfaceDetailsFragment = EthernetInterfaceDetailsFragment() + + private val context: Context = + object : ContextWrapper(ApplicationProvider.getApplicationContext()) {} + + private val ethernetInterfaceDetailsController = + EthernetInterfaceDetailsController(context, ethernetInterfaceDetailsFragment, "eth0") + + @Test + fun isAvailable_ShouldReturnTrue() { + assertTrue(ethernetInterfaceDetailsController.isAvailable()) + } + + @Test + fun getPreferencKey_shouldReturnExpectedKey() { + assertEquals(ethernetInterfaceDetailsController.getPreferenceKey(), "ethernet_details") + } +} diff --git a/tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsFragmentTest.kt b/tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsFragmentTest.kt new file mode 100644 index 00000000000..8bf03b96d69 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/ethernet/EthernetInterfaceDetailsFragmentTest.kt @@ -0,0 +1,69 @@ +/* + * 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.app.settings.SettingsEnums +import android.content.Context +import android.content.ContextWrapper +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settingslib.core.AbstractPreferenceController +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class EthernetInterfaceDetailsFragmentTest { + private val ethernetInterfaceDetailsFragment = EthernetInterfaceDetailsFragment() + + private val context: Context = + object : ContextWrapper(ApplicationProvider.getApplicationContext()) {} + + @Test + fun getMetricsCategory_shouldReturnEthernetSettings() { + assertEquals( + ethernetInterfaceDetailsFragment.getMetricsCategory(), + SettingsEnums.ETHERNET_SETTINGS, + ) + } + + @Test + fun getPreferenceScreenId_shouldReturnExpectedResource() { + assertEquals( + ethernetInterfaceDetailsFragment.getPreferenceScreenResId(), + R.xml.ethernet_interface_details, + ) + } + + @Test + fun getLogTag_shouldReturnClassName() { + assertEquals( + ethernetInterfaceDetailsFragment.getLogTag(), + "EthernetInterfaceDetailsFragment", + ) + } + + @Test + fun createPreferenceController_shouldReturnDetailController() { + val preferenceController = + ethernetInterfaceDetailsFragment.createPreferenceControllers(context) + assertEquals(1, preferenceController.size) + assertTrue(preferenceController[0] is AbstractPreferenceController) + } +}