Merge "Add ethernet interface details settings subpage" into main
diff --git a/res/xml/ethernet_interface_details.xml b/res/xml/ethernet_interface_details.xml
new file mode 100644
index 0000000..f2d106f
--- /dev/null
+++ b/res/xml/ethernet_interface_details.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto">
+
+    <com.android.settingslib.widget.LayoutPreference
+        android:key="connection_header"
+        android:layout="@layout/settings_entity_header"
+        android:selectable="false"
+        android:order="-10000"/>
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index f0f9470..3f9d495 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.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 @@
         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 @@
                         (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);
@@ -1174,6 +1178,20 @@
     }
 
     @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 0000000..cb3ad1d
--- /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 0000000..a6cf90f
--- /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<AbstractPreferenceController> {
+        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 0000000..fb8e476
--- /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 0000000..8bf03b9
--- /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)
+    }
+}