1 /* 2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.network.ethernet 18 19 import android.content.Context 20 import android.net.ConnectivityManager 21 import android.net.ConnectivityManager.NetworkCallback 22 import android.net.EthernetManager 23 import android.net.EthernetManager.STATE_ABSENT 24 import android.net.EthernetNetworkManagementException 25 import android.net.EthernetNetworkUpdateRequest 26 import android.net.IpConfiguration 27 import android.net.LinkProperties 28 import android.net.Network 29 import android.net.NetworkCapabilities 30 import android.net.NetworkRequest 31 import android.os.OutcomeReceiver 32 import android.util.Log 33 import androidx.core.content.ContextCompat 34 import com.google.common.annotations.VisibleForTesting 35 36 class EthernetInterface(private val context: Context, private val id: String) : 37 EthernetManager.InterfaceStateListener { 38 interface EthernetInterfaceStateListener { interfaceUpdatednull39 fun interfaceUpdated() 40 } 41 42 private val ethernetManager: EthernetManager? = 43 context.getSystemService(EthernetManager::class.java) 44 private val connectivityManager: ConnectivityManager? = 45 context.getSystemService(ConnectivityManager::class.java) 46 private val executor = ContextCompat.getMainExecutor(context) 47 private val interfaceListeners = mutableListOf<EthernetInterfaceStateListener>() 48 49 private val TAG = "EthernetInterface" 50 51 private val networkRequest: NetworkRequest = 52 NetworkRequest.Builder() 53 .clearCapabilities() 54 .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) 55 .build() 56 57 private var interfaceState = STATE_ABSENT 58 private var ipConfiguration = IpConfiguration() 59 private var linkProperties = LinkProperties() 60 61 fun getInterfaceState() = interfaceState 62 63 fun getId() = id 64 65 fun getConfiguration() = ipConfiguration 66 67 fun getLinkProperties() = linkProperties 68 69 fun registerListener(listener: EthernetInterfaceStateListener) { 70 if (interfaceListeners.isEmpty()) { 71 ethernetManager?.addInterfaceStateListener(ContextCompat.getMainExecutor(context), this) 72 connectivityManager?.registerNetworkCallback(networkRequest, networkCallback) 73 } 74 interfaceListeners.add(listener) 75 } 76 unregisterListenernull77 fun unregisterListener(listener: EthernetInterfaceStateListener) { 78 interfaceListeners.remove(listener) 79 if (interfaceListeners.isEmpty()) { 80 connectivityManager?.unregisterNetworkCallback(networkCallback) 81 ethernetManager?.removeInterfaceStateListener(this) 82 } 83 } 84 setConfigurationnull85 fun setConfiguration(ipConfiguration: IpConfiguration) { 86 val request = 87 EthernetNetworkUpdateRequest.Builder().setIpConfiguration(ipConfiguration).build() 88 ethernetManager?.updateConfiguration( 89 id, 90 request, 91 executor, 92 object : OutcomeReceiver<String, EthernetNetworkManagementException> { 93 override fun onError(e: EthernetNetworkManagementException) { 94 Log.e(TAG, "Failed to updateConfiguration: ", e) 95 } 96 97 override fun onResult(id: String) { 98 Log.d(TAG, "Successfully updated configuration: " + id) 99 } 100 }, 101 ) 102 } 103 notifyListenersnull104 private fun notifyListeners() { 105 for (listener in interfaceListeners) { 106 listener.interfaceUpdated() 107 } 108 } 109 onInterfaceStateChangednull110 override fun onInterfaceStateChanged(id: String, state: Int, role: Int, cfg: IpConfiguration?) { 111 if (id == this.id) { 112 ipConfiguration = cfg ?: IpConfiguration() 113 interfaceState = state 114 notifyListeners() 115 } 116 } 117 118 @VisibleForTesting 119 val networkCallback = 120 object : NetworkCallback() { onLinkPropertiesChangednull121 override fun onLinkPropertiesChanged(network: Network, lp: LinkProperties) { 122 if (lp.getInterfaceName().equals(id)) { 123 linkProperties = lp 124 notifyListeners() 125 } 126 } 127 } 128 } 129