1 /*
2  * Copyright 2021 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.internal.telephony.data;
18 
19 import android.annotation.CurrentTimeMillisLong;
20 import android.annotation.ElapsedRealtimeLong;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.net.NetworkAgent;
24 import android.net.NetworkCapabilities;
25 import android.os.SystemClock;
26 import android.telephony.AccessNetworkConstants;
27 import android.telephony.AccessNetworkConstants.AccessNetworkType;
28 import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
29 import android.telephony.AccessNetworkConstants.TransportType;
30 import android.telephony.Annotation.ConnectivityTransport;
31 import android.telephony.Annotation.DataActivityType;
32 import android.telephony.Annotation.NetCapability;
33 import android.telephony.Annotation.NetworkType;
34 import android.telephony.Annotation.ValidationStatus;
35 import android.telephony.TelephonyManager;
36 import android.telephony.data.ApnSetting;
37 import android.telephony.data.ApnSetting.ApnType;
38 import android.telephony.data.DataCallResponse;
39 import android.telephony.data.DataCallResponse.LinkStatus;
40 import android.telephony.ims.feature.ImsFeature;
41 import android.util.ArrayMap;
42 
43 import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList;
44 import com.android.internal.telephony.flags.FeatureFlags;
45 import com.android.telephony.Rlog;
46 
47 import java.text.SimpleDateFormat;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collection;
51 import java.util.Collections;
52 import java.util.List;
53 import java.util.Locale;
54 import java.util.Map;
55 import java.util.Set;
56 import java.util.stream.Collectors;
57 
58 /**
59  * This class contains all the utility methods used by telephony data stack.
60  */
61 public class DataUtils {
62     public static final int NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED = 37;
63     /** The time format for converting time to readable string. */
64     private static final SimpleDateFormat TIME_FORMAT =
65             new SimpleDateFormat("HH:mm:ss.SSS", Locale.US);
66     private static final String TAG = "DataUtils";
67 
68     /**
69      * Get the network capability from the string.
70      *
71      * @param capabilityString The capability in string format
72      * @return The network capability. -1 if not found.
73      */
74     @NetCapability
getNetworkCapabilityFromString(@onNull String capabilityString)75     public static int getNetworkCapabilityFromString(@NonNull String capabilityString) {
76         return switch (capabilityString.toUpperCase(Locale.ROOT)) {
77             case "MMS" -> NetworkCapabilities.NET_CAPABILITY_MMS;
78             case "SUPL" -> NetworkCapabilities.NET_CAPABILITY_SUPL;
79             case "DUN" -> NetworkCapabilities.NET_CAPABILITY_DUN;
80             case "FOTA" -> NetworkCapabilities.NET_CAPABILITY_FOTA;
81             case "IMS" -> NetworkCapabilities.NET_CAPABILITY_IMS;
82             case "CBS" -> NetworkCapabilities.NET_CAPABILITY_CBS;
83             case "XCAP" -> NetworkCapabilities.NET_CAPABILITY_XCAP;
84             case "EIMS" -> NetworkCapabilities.NET_CAPABILITY_EIMS;
85             case "INTERNET" -> NetworkCapabilities.NET_CAPABILITY_INTERNET;
86             case "MCX" -> NetworkCapabilities.NET_CAPABILITY_MCX;
87             case "VSIM" -> NetworkCapabilities.NET_CAPABILITY_VSIM;
88             case "BIP" -> NetworkCapabilities.NET_CAPABILITY_BIP;
89             case "ENTERPRISE" -> NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
90             case "PRIORITIZE_BANDWIDTH" -> NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH;
91             case "PRIORITIZE_LATENCY" -> NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY;
92             case "RCS" -> NetworkCapabilities.NET_CAPABILITY_RCS;
93             default -> {
94                 loge("Illegal network capability: " + capabilityString);
95                 yield -1;
96             }
97         };
98     }
99 
100     /**
101      * Get Set of network capabilities from string joined by {@code |}, space is ignored.
102      * If input string contains unknown capability or malformatted(e.g. empty string), -1 is
103      * included in the returned set.
104      *
105      * @param capabilitiesString capability strings joined by {@code |}
106      * @return Set of capabilities
107      */
108     @NetCapability
getNetworkCapabilitiesFromString( @onNull String capabilitiesString)109     public static Set<Integer> getNetworkCapabilitiesFromString(
110             @NonNull String capabilitiesString) {
111         // e.g. "IMS|" is not allowed
112         if (!capabilitiesString.matches("(\\s*[a-zA-Z_]+\\s*)(\\|\\s*[a-zA-Z_]+\\s*)*")) {
113             return Collections.singleton(-1);
114         }
115         return Arrays.stream(capabilitiesString.split("\\s*\\|\\s*"))
116                 .map(String::trim)
117                 .map(DataUtils::getNetworkCapabilityFromString)
118                 .collect(Collectors.toSet());
119     }
120 
121     /**
122      * Convert a network capability to string.
123      * <p>
124      * This is for debugging and logging purposes only.
125      *
126      * @param netCap Network capability.
127      * @return Network capability in string format.
128      */
129     @NonNull
networkCapabilityToString(@etCapability int netCap)130     public static String networkCapabilityToString(@NetCapability int netCap) {
131         return switch (netCap) {
132             case NetworkCapabilities.NET_CAPABILITY_MMS -> "MMS";
133             case NetworkCapabilities.NET_CAPABILITY_SUPL -> "SUPL";
134             case NetworkCapabilities.NET_CAPABILITY_DUN -> "DUN";
135             case NetworkCapabilities.NET_CAPABILITY_FOTA -> "FOTA";
136             case NetworkCapabilities.NET_CAPABILITY_IMS -> "IMS";
137             case NetworkCapabilities.NET_CAPABILITY_CBS -> "CBS";
138             case NetworkCapabilities.NET_CAPABILITY_WIFI_P2P -> "WIFI_P2P";
139             case NetworkCapabilities.NET_CAPABILITY_IA -> "IA";
140             case NetworkCapabilities.NET_CAPABILITY_RCS -> "RCS";
141             case NetworkCapabilities.NET_CAPABILITY_XCAP -> "XCAP";
142             case NetworkCapabilities.NET_CAPABILITY_EIMS -> "EIMS";
143             case NetworkCapabilities.NET_CAPABILITY_NOT_METERED -> "NOT_METERED";
144             case NetworkCapabilities.NET_CAPABILITY_INTERNET -> "INTERNET";
145             case NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED -> "NOT_RESTRICTED";
146             case NetworkCapabilities.NET_CAPABILITY_TRUSTED -> "TRUSTED";
147             case NetworkCapabilities.NET_CAPABILITY_NOT_VPN -> "NOT_VPN";
148             case NetworkCapabilities.NET_CAPABILITY_VALIDATED -> "VALIDATED";
149             case NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL -> "CAPTIVE_PORTAL";
150             case NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING -> "NOT_ROAMING";
151             case NetworkCapabilities.NET_CAPABILITY_FOREGROUND -> "FOREGROUND";
152             case NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED -> "NOT_CONGESTED";
153             case NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED -> "NOT_SUSPENDED";
154             case NetworkCapabilities.NET_CAPABILITY_OEM_PAID -> "OEM_PAID";
155             case NetworkCapabilities.NET_CAPABILITY_MCX -> "MCX";
156             case NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY -> "PARTIAL_CONNECTIVITY";
157             case NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED ->
158                     "TEMPORARILY_NOT_METERED";
159             case NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE -> "OEM_PRIVATE";
160             case NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL -> "VEHICLE_INTERNAL";
161             case NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED -> "NOT_VCN_MANAGED";
162             case NetworkCapabilities.NET_CAPABILITY_ENTERPRISE -> "ENTERPRISE";
163             case NetworkCapabilities.NET_CAPABILITY_VSIM -> "VSIM";
164             case NetworkCapabilities.NET_CAPABILITY_BIP -> "BIP";
165             case NetworkCapabilities.NET_CAPABILITY_HEAD_UNIT -> "HEAD_UNIT";
166             case NetworkCapabilities.NET_CAPABILITY_MMTEL -> "MMTEL";
167             case NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY -> "PRIORITIZE_LATENCY";
168             case NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH -> "PRIORITIZE_BANDWIDTH";
169             case NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED -> "NOT_BANDWIDTH_CONSTRAINED";
170             default -> {
171                 loge("Unknown network capability(" + netCap + ")");
172                 yield "Unknown(" + netCap + ")";
173             }
174         };
175     }
176 
177     /**
178      * Concat an array of {@link NetworkCapabilities.Transport} in string format.
179      *
180      * @param transports an array of connectivity transports
181      * @return a string of the array of transports.
182      */
183     @NonNull
184     public static String connectivityTransportsToString(
185             @NonNull @ConnectivityTransport int[] transports) {
186         return Arrays.stream(transports).mapToObj(DataUtils::connectivityTransportToString)
187                 .collect(Collectors.joining("|"));
188     }
189 
190     /**
191      * Convert a {@link NetworkCapabilities.Transport} to a string.
192      *
193      * @param transport the connectivity transport
194      * @return the transport in string
195      */
196     @NonNull
197     public static String connectivityTransportToString(
198             @ConnectivityTransport int transport) {
199         return switch (transport) {
200             case NetworkCapabilities.TRANSPORT_CELLULAR -> "CELLULAR";
201             case NetworkCapabilities.TRANSPORT_WIFI -> "WIFI";
202             case NetworkCapabilities.TRANSPORT_BLUETOOTH -> "BLUETOOTH";
203             case NetworkCapabilities.TRANSPORT_ETHERNET -> "ETHERNET";
204             case NetworkCapabilities.TRANSPORT_VPN -> "VPN";
205             case NetworkCapabilities.TRANSPORT_WIFI_AWARE -> "WIFI_AWARE";
206             case NetworkCapabilities.TRANSPORT_LOWPAN -> "LOWPAN";
207             case NetworkCapabilities.TRANSPORT_TEST -> "TEST";
208             case NetworkCapabilities.TRANSPORT_USB -> "USB";
209             case NetworkCapabilities.TRANSPORT_THREAD -> "THREAD";
210             case NetworkCapabilities.TRANSPORT_SATELLITE -> "SATELLITE";
211             default -> "Unknown(" + transport + ")";
212         };
213     }
214 
215     /**
216      * Convert network capabilities to string.
217      * <p>
218      * This is for debugging and logging purposes only.
219      *
220      * @param netCaps Network capabilities.
221      * @return Network capabilities in string format.
222      */
223     @NonNull
224     public static String networkCapabilitiesToString(
225             @NetCapability @Nullable Collection<Integer> netCaps) {
226         if (netCaps == null || netCaps.isEmpty()) return "";
227         return "[" + netCaps.stream()
228                 .map(DataUtils::networkCapabilityToString)
229                 .collect(Collectors.joining("|")) + "]";
230     }
231 
232     /**
233      * Convert network capabilities to string.
234      * <p>
235      * This is for debugging and logging purposes only.
236      *
237      * @param netCaps Network capabilities.
238      * @return Network capabilities in string format.
239      */
240     @NonNull
241     public static String networkCapabilitiesToString(@NetCapability int[] netCaps) {
242         if (netCaps == null) return "";
243         return "[" + Arrays.stream(netCaps)
244                 .mapToObj(DataUtils::networkCapabilityToString)
245                 .collect(Collectors.joining("|")) + "]";
246     }
247 
248     /**
249      * Convert the validation status to string.
250      *
251      * @param status The validation status.
252      * @return The validation status in string format.
253      */
254     @NonNull
255     public static String validationStatusToString(@ValidationStatus int status) {
256         return switch (status) {
257             case NetworkAgent.VALIDATION_STATUS_VALID -> "VALID";
258             case NetworkAgent.VALIDATION_STATUS_NOT_VALID -> "INVALID";
259             default -> {
260                 loge("Unknown validation status(" + status + ")");
261                 yield "UNKNOWN(" + status + ")";
262             }
263         };
264     }
265 
266     /**
267      * Convert network capability into APN type.
268      *
269      * @param networkCapability Network capability.
270      * @return APN type.
271      */
272     @ApnType
273     public static int networkCapabilityToApnType(@NetCapability int networkCapability) {
274         return switch (networkCapability) {
275             case NetworkCapabilities.NET_CAPABILITY_MMS -> ApnSetting.TYPE_MMS;
276             case NetworkCapabilities.NET_CAPABILITY_SUPL -> ApnSetting.TYPE_SUPL;
277             case NetworkCapabilities.NET_CAPABILITY_DUN -> ApnSetting.TYPE_DUN;
278             case NetworkCapabilities.NET_CAPABILITY_FOTA -> ApnSetting.TYPE_FOTA;
279             case NetworkCapabilities.NET_CAPABILITY_IMS -> ApnSetting.TYPE_IMS;
280             case NetworkCapabilities.NET_CAPABILITY_CBS -> ApnSetting.TYPE_CBS;
281             case NetworkCapabilities.NET_CAPABILITY_XCAP -> ApnSetting.TYPE_XCAP;
282             case NetworkCapabilities.NET_CAPABILITY_EIMS -> ApnSetting.TYPE_EMERGENCY;
283             case NetworkCapabilities.NET_CAPABILITY_INTERNET -> ApnSetting.TYPE_DEFAULT;
284             case NetworkCapabilities.NET_CAPABILITY_MCX -> ApnSetting.TYPE_MCX;
285             case NetworkCapabilities.NET_CAPABILITY_IA -> ApnSetting.TYPE_IA;
286             case NetworkCapabilities.NET_CAPABILITY_ENTERPRISE -> ApnSetting.TYPE_ENTERPRISE;
287             case NetworkCapabilities.NET_CAPABILITY_VSIM -> ApnSetting.TYPE_VSIM;
288             case NetworkCapabilities.NET_CAPABILITY_BIP -> ApnSetting.TYPE_BIP;
289             case NetworkCapabilities.NET_CAPABILITY_RCS -> ApnSetting.TYPE_RCS;
290             default -> ApnSetting.TYPE_NONE;
291         };
292     }
293 
294     /**
295      * Convert APN type to capability.
296      *
297      * @param apnType APN type.
298      * @return Network capability.
299      */
300     @NetCapability
301     public static int apnTypeToNetworkCapability(@ApnType int apnType) {
302         return switch (apnType) {
303             case ApnSetting.TYPE_MMS -> NetworkCapabilities.NET_CAPABILITY_MMS;
304             case ApnSetting.TYPE_SUPL -> NetworkCapabilities.NET_CAPABILITY_SUPL;
305             case ApnSetting.TYPE_DUN -> NetworkCapabilities.NET_CAPABILITY_DUN;
306             case ApnSetting.TYPE_FOTA -> NetworkCapabilities.NET_CAPABILITY_FOTA;
307             case ApnSetting.TYPE_IMS -> NetworkCapabilities.NET_CAPABILITY_IMS;
308             case ApnSetting.TYPE_CBS -> NetworkCapabilities.NET_CAPABILITY_CBS;
309             case ApnSetting.TYPE_XCAP -> NetworkCapabilities.NET_CAPABILITY_XCAP;
310             case ApnSetting.TYPE_EMERGENCY -> NetworkCapabilities.NET_CAPABILITY_EIMS;
311             case ApnSetting.TYPE_DEFAULT -> NetworkCapabilities.NET_CAPABILITY_INTERNET;
312             case ApnSetting.TYPE_MCX -> NetworkCapabilities.NET_CAPABILITY_MCX;
313             case ApnSetting.TYPE_IA -> NetworkCapabilities.NET_CAPABILITY_IA;
314             case ApnSetting.TYPE_BIP -> NetworkCapabilities.NET_CAPABILITY_BIP;
315             case ApnSetting.TYPE_VSIM -> NetworkCapabilities.NET_CAPABILITY_VSIM;
316             case ApnSetting.TYPE_ENTERPRISE -> NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
317             case ApnSetting.TYPE_RCS -> NetworkCapabilities.NET_CAPABILITY_RCS;
318             default -> -1;
319         };
320     }
321 
322     /**
323      * Convert network type to access network type.
324      *
325      * @param networkType The network type.
326      * @return The access network type.
327      */
328     @RadioAccessNetworkType
329     public static int networkTypeToAccessNetworkType(@NetworkType int networkType) {
330         return switch (networkType) {
331             case TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_EDGE,
332                     TelephonyManager.NETWORK_TYPE_GSM ->
333                     AccessNetworkType.GERAN;
334             case TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_HSDPA,
335                     TelephonyManager.NETWORK_TYPE_HSPAP, TelephonyManager.NETWORK_TYPE_HSUPA,
336                     TelephonyManager.NETWORK_TYPE_HSPA, TelephonyManager.NETWORK_TYPE_TD_SCDMA ->
337                     AccessNetworkType.UTRAN;
338             case TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_EVDO_0,
339                     TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_EVDO_B,
340                     TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyManager.NETWORK_TYPE_EHRPD ->
341                     AccessNetworkType.CDMA2000;
342             case TelephonyManager.NETWORK_TYPE_LTE, TelephonyManager.NETWORK_TYPE_LTE_CA ->
343                     AccessNetworkType.EUTRAN;
344             case TelephonyManager.NETWORK_TYPE_IWLAN -> AccessNetworkType.IWLAN;
345             case TelephonyManager.NETWORK_TYPE_NR -> AccessNetworkType.NGRAN;
346             default -> AccessNetworkType.UNKNOWN;
347         };
348     }
349 
350     /**
351      * Convert the elapsed time to the current time with readable time format.
352      *
353      * @param elapsedTime The elapsed time retrieved from {@link SystemClock#elapsedRealtime()}.
354      * @return The string format time.
355      */
356     @NonNull
357     public static String elapsedTimeToString(@ElapsedRealtimeLong long elapsedTime) {
358         return (elapsedTime != 0) ? systemTimeToString(System.currentTimeMillis()
359                 - SystemClock.elapsedRealtime() + elapsedTime) : "never";
360     }
361 
362     /**
363      * Convert the system time to the human readable format.
364      *
365      * @param systemTime The system time retrieved from {@link System#currentTimeMillis()}.
366      * @return The string format time.
367      */
368     @NonNull
369     public static String systemTimeToString(@CurrentTimeMillisLong long systemTime) {
370         return (systemTime != 0) ? TIME_FORMAT.format(systemTime) : "never";
371     }
372 
373     /**
374      * Convert the IMS feature to string.
375      *
376      * @param imsFeature IMS feature.
377      * @return IMS feature in string format.
378      */
379     @NonNull
380     public static String imsFeatureToString(@ImsFeature.FeatureType int imsFeature) {
381         return switch (imsFeature) {
382             case ImsFeature.FEATURE_MMTEL -> "MMTEL";
383             case ImsFeature.FEATURE_RCS -> "RCS";
384             default -> {
385                 loge("Unknown IMS feature(" + imsFeature + ")");
386                 yield "Unknown(" + imsFeature + ")";
387             }
388         };
389     }
390 
391     /**
392      * Group the network requests into several list that contains the same network capabilities.
393      *
394      * @param networkRequestList The provided network requests.
395      * @param featureFlags The feature flag.
396      *
397      * @return The network requests after grouping.
398      */
399     @NonNull
400     public static List<NetworkRequestList> getGroupedNetworkRequestList(
401             @NonNull NetworkRequestList networkRequestList, @NonNull FeatureFlags featureFlags) {
402         List<NetworkRequestList> requests = new ArrayList<>();
403         if (featureFlags.satelliteInternet()) {
404             record NetworkCapabilitiesKey(Set<Integer> caps, Set<Integer> enterpriseIds,
405                                           Set<Integer> transportTypes) { }
406 
407             // Key is the combination of capabilities, enterprise ids, and transport types.
408             Map<NetworkCapabilitiesKey, NetworkRequestList> requestsMap = new ArrayMap<>();
409             for (TelephonyNetworkRequest networkRequest : networkRequestList) {
410                 requestsMap.computeIfAbsent(new NetworkCapabilitiesKey(
411                                 Arrays.stream(networkRequest.getCapabilities())
412                                         .boxed().collect(Collectors.toSet()),
413                                 Arrays.stream(networkRequest.getNativeNetworkRequest()
414                                                 .getEnterpriseIds())
415                                         .boxed().collect(Collectors.toSet()),
416                                 Arrays.stream(networkRequest.getTransportTypes())
417                                         .boxed().collect(Collectors.toSet())
418                                 ),
419                         v -> new NetworkRequestList()).add(networkRequest);
420             }
421             requests.addAll(requestsMap.values());
422         } else {
423             // Key is the capabilities set.
424             Map<Set<Integer>, NetworkRequestList> requestsMap = new ArrayMap<>();
425             for (TelephonyNetworkRequest networkRequest : networkRequestList) {
426                 requestsMap.computeIfAbsent(Arrays.stream(networkRequest.getCapabilities())
427                                 .boxed().collect(Collectors.toSet()),
428                         v -> new NetworkRequestList()).add(networkRequest);
429             }
430             // Create separate groups for enterprise requests with different enterprise IDs.
431             for (NetworkRequestList requestList : requestsMap.values()) {
432                 List<TelephonyNetworkRequest> enterpriseRequests = requestList.stream()
433                         .filter(request -> request.hasCapability(
434                                 NetworkCapabilities.NET_CAPABILITY_ENTERPRISE))
435                         .toList();
436                 if (enterpriseRequests.isEmpty()) {
437                     requests.add(requestList);
438                     continue;
439                 }
440                 // Key is the enterprise ID
441                 Map<Integer, NetworkRequestList> enterpriseRequestsMap = new ArrayMap<>();
442                 for (TelephonyNetworkRequest request : enterpriseRequests) {
443                     enterpriseRequestsMap.computeIfAbsent(request.getCapabilityDifferentiator(),
444                             v -> new NetworkRequestList()).add(request);
445                 }
446                 requests.addAll(enterpriseRequestsMap.values());
447             }
448         }
449         // Sort the requests so the network request list with higher priority will be at the front.
450         return requests.stream()
451                 .sorted((list1, list2) -> Integer.compare(
452                         list2.get(0).getPriority(), list1.get(0).getPriority()))
453                 .collect(Collectors.toList());
454     }
455 
456     /**
457      * Get the target transport from source transport. This is only used for handover between
458      * IWLAN and cellular scenario.
459      *
460      * @param sourceTransport The source transport.
461      * @return The target transport.
462      */
463     @TransportType
464     public static int getTargetTransport(@TransportType int sourceTransport) {
465         return sourceTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
466                 ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN
467                 : AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
468     }
469 
470     /**
471      * Convert link status to string.
472      *
473      * @param linkStatus The link status.
474      * @return The link status in string format.
475      */
476     @NonNull
477     public static String linkStatusToString(@LinkStatus int linkStatus) {
478         return switch (linkStatus) {
479             case DataCallResponse.LINK_STATUS_UNKNOWN -> "UNKNOWN";
480             case DataCallResponse.LINK_STATUS_INACTIVE -> "INACTIVE";
481             case DataCallResponse.LINK_STATUS_ACTIVE -> "ACTIVE";
482             case DataCallResponse.LINK_STATUS_DORMANT -> "DORMANT";
483             default -> {
484                 loge("Unknown link status(" + linkStatus + ")");
485                 yield "UNKNOWN(" + linkStatus + ")";
486             }
487         };
488     }
489 
490     /**
491      * Check if access network type is valid.
492      *
493      * @param accessNetworkType The access network type to check.
494      * @return {@code true} if the access network type is valid.
495      */
496     public static boolean isValidAccessNetwork(@RadioAccessNetworkType int accessNetworkType) {
497         return switch (accessNetworkType) {
498             case AccessNetworkType.GERAN, AccessNetworkType.UTRAN, AccessNetworkType.EUTRAN,
499                     AccessNetworkType.CDMA2000, AccessNetworkType.IWLAN, AccessNetworkType.NGRAN ->
500                     true;
501             default -> false;
502         };
503     }
504 
505     /**
506      * Convert data activity to string.
507      *
508      * @param dataActivity The data activity.
509      * @return The data activity in string format.
510      */
511     @NonNull
512     public static String dataActivityToString(@DataActivityType int dataActivity) {
513         return switch (dataActivity) {
514             case TelephonyManager.DATA_ACTIVITY_NONE -> "NONE";
515             case TelephonyManager.DATA_ACTIVITY_IN -> "IN";
516             case TelephonyManager.DATA_ACTIVITY_OUT -> "OUT";
517             case TelephonyManager.DATA_ACTIVITY_INOUT -> "INOUT";
518             case TelephonyManager.DATA_ACTIVITY_DORMANT -> "DORMANT";
519             default -> {
520                 loge("Unknown data activity(" + dataActivity + ")");
521                 yield "UNKNOWN(" + dataActivity + ")";
522             }
523         };
524     }
525 
526     private static void loge(String msg) {
527         Rlog.e(TAG, msg);
528     }
529 }
530