1 /* 2 * Copyright 2023 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 androidx.work.impl.utils 18 19 import android.net.NetworkCapabilities 20 import android.net.NetworkRequest 21 import android.os.Build 22 import androidx.annotation.RequiresApi 23 import androidx.work.Logger 24 25 internal data class NetworkRequestCompat(val wrapped: Any? = null) { 26 27 companion object { 28 val TAG = Logger.tagWithPrefix("NetworkRequestCompat") 29 } 30 31 @get:RequiresApi(21) 32 val networkRequest: NetworkRequest? 33 get() = wrapped as NetworkRequest? 34 } 35 36 @get:RequiresApi(28) 37 val NetworkRequest.transportTypesCompat: IntArray 38 get() = 39 if (Build.VERSION.SDK_INT >= 31) { 40 NetworkRequest31.transportTypes(this) 41 } else { 42 intArrayOf( 43 NetworkCapabilities.TRANSPORT_BLUETOOTH, 44 NetworkCapabilities.TRANSPORT_CELLULAR, 45 NetworkCapabilities.TRANSPORT_ETHERNET, 46 NetworkCapabilities.TRANSPORT_LOWPAN, 47 NetworkCapabilities.TRANSPORT_THREAD, 48 NetworkCapabilities.TRANSPORT_USB, 49 NetworkCapabilities.TRANSPORT_VPN, 50 NetworkCapabilities.TRANSPORT_WIFI, 51 NetworkCapabilities.TRANSPORT_WIFI_AWARE, 52 ) <lambda>null53 .filter { NetworkRequest28.hasTransport(this, it) } 54 .toIntArray() 55 } 56 57 @get:RequiresApi(28) 58 val NetworkRequest.capabilitiesCompat: IntArray 59 get() = 60 if (Build.VERSION.SDK_INT >= 31) { 61 NetworkRequest31.capabilities(this) 62 } else { 63 intArrayOf( 64 NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL, 65 NetworkCapabilities.NET_CAPABILITY_CBS, 66 NetworkCapabilities.NET_CAPABILITY_DUN, 67 NetworkCapabilities.NET_CAPABILITY_EIMS, 68 NetworkCapabilities.NET_CAPABILITY_ENTERPRISE, 69 NetworkCapabilities.NET_CAPABILITY_FOREGROUND, 70 NetworkCapabilities.NET_CAPABILITY_FOTA, 71 NetworkCapabilities.NET_CAPABILITY_HEAD_UNIT, 72 NetworkCapabilities.NET_CAPABILITY_IA, 73 NetworkCapabilities.NET_CAPABILITY_IMS, 74 NetworkCapabilities.NET_CAPABILITY_INTERNET, 75 NetworkCapabilities.NET_CAPABILITY_MCX, 76 NetworkCapabilities.NET_CAPABILITY_MMS, 77 NetworkCapabilities.NET_CAPABILITY_MMTEL, 78 NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED, 79 NetworkCapabilities.NET_CAPABILITY_NOT_METERED, 80 NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED, 81 NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, 82 NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED, 83 NetworkCapabilities.NET_CAPABILITY_NOT_VPN, 84 NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH, 85 NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY, 86 NetworkCapabilities.NET_CAPABILITY_RCS, 87 NetworkCapabilities.NET_CAPABILITY_SUPL, 88 NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED, 89 NetworkCapabilities.NET_CAPABILITY_TRUSTED, 90 NetworkCapabilities.NET_CAPABILITY_VALIDATED, 91 NetworkCapabilities.NET_CAPABILITY_WIFI_P2P, 92 NetworkCapabilities.NET_CAPABILITY_XCAP, 93 ) <lambda>null94 .filter { NetworkRequest28.hasCapability(this, it) } 95 .toIntArray() 96 } 97 98 @RequiresApi(28) 99 object NetworkRequest28 { hasCapabilitynull100 internal fun hasCapability(request: NetworkRequest, capability: Int) = 101 request.hasCapability(capability) 102 103 internal fun hasTransport(request: NetworkRequest, transport: Int) = 104 request.hasTransport(transport) 105 106 @JvmStatic 107 fun createNetworkRequest(capabilities: IntArray, transports: IntArray): NetworkRequest { 108 val networkRequest = NetworkRequest.Builder() 109 capabilities.forEach { 110 try { 111 networkRequest.addCapability(it) 112 } catch (ex: IllegalArgumentException) { 113 // b/351180465 - Ignoring the IAE that addCapability() can throw on SDK < 35 and 114 // aligning with newer SDK behaviour. Capabilities are persisted in the database 115 // and the framework can by default add new ones. Catching this exception mitigates 116 // the case where decoding the capabilities from the database fails across OS 117 // changes. 118 Logger.get() 119 .warning(NetworkRequestCompat.TAG, "Ignoring adding capability '$it'", ex) 120 } 121 } 122 transports.forEach { networkRequest.addTransportType(it) } 123 return networkRequest.build() 124 } 125 createNetworkRequestCompatnull126 internal fun createNetworkRequestCompat( 127 capabilities: IntArray, 128 transports: IntArray 129 ): NetworkRequestCompat { 130 return NetworkRequestCompat(createNetworkRequest(capabilities, transports)) 131 } 132 } 133 134 @RequiresApi(31) 135 private object NetworkRequest31 { capabilitiesnull136 fun capabilities(request: NetworkRequest) = request.capabilities 137 138 fun transportTypes(request: NetworkRequest) = request.transportTypes 139 } 140 141 @RequiresApi(30) 142 internal object NetworkRequest30 { 143 fun getNetworkSpecifier(request: NetworkRequest) = request.networkSpecifier 144 } 145