File: NetworkCapabilities.java

package info (click to toggle)
android-platform-frameworks-base 1%3A10.0.0%2Br36-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 321,788 kB
  • sloc: java: 962,234; cpp: 274,314; xml: 242,770; python: 5,060; sh: 1,432; ansic: 494; makefile: 47; sed: 19
file content (1709 lines) | stat: -rw-r--r-- 65,398 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
/*
 * Copyright (C) 2014 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 android.net;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.BitUtils;
import com.android.internal.util.Preconditions;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;

/**
 * Representation of the capabilities of an active network. Instances are
 * typically obtained through
 * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
 * or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
 * <p>
 * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
 * network selection. Rather than indicate a need for Wi-Fi because an
 * application needs high bandwidth and risk obsolescence when a new, fast
 * network appears (like LTE), the application should specify it needs high
 * bandwidth. Similarly if an application needs an unmetered network for a bulk
 * transfer it can specify that rather than assuming all cellular based
 * connections are metered and all Wi-Fi based connections are not.
 */
public final class NetworkCapabilities implements Parcelable {
    private static final String TAG = "NetworkCapabilities";
    private static final int INVALID_UID = -1;

    /**
     * @hide
     */
    @UnsupportedAppUsage
    public NetworkCapabilities() {
        clearAll();
        mNetworkCapabilities = DEFAULT_CAPABILITIES;
    }

    public NetworkCapabilities(NetworkCapabilities nc) {
        if (nc != null) {
            set(nc);
        }
    }

    /**
     * Completely clears the contents of this object, removing even the capabilities that are set
     * by default when the object is constructed.
     * @hide
     */
    public void clearAll() {
        mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
        mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
        mNetworkSpecifier = null;
        mTransportInfo = null;
        mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
        mUids = null;
        mEstablishingVpnAppUid = INVALID_UID;
        mSSID = null;
    }

    /**
     * Set all contents of this object to the contents of a NetworkCapabilities.
     * @hide
     */
    public void set(@NonNull NetworkCapabilities nc) {
        mNetworkCapabilities = nc.mNetworkCapabilities;
        mTransportTypes = nc.mTransportTypes;
        mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
        mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
        mNetworkSpecifier = nc.mNetworkSpecifier;
        mTransportInfo = nc.mTransportInfo;
        mSignalStrength = nc.mSignalStrength;
        setUids(nc.mUids); // Will make the defensive copy
        mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
        mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
        mSSID = nc.mSSID;
    }

    /**
     * Represents the network's capabilities.  If any are specified they will be satisfied
     * by any Network that matches all of them.
     */
    @UnsupportedAppUsage
    private long mNetworkCapabilities;

    /**
     * If any capabilities specified here they must not exist in the matching Network.
     */
    private long mUnwantedNetworkCapabilities;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = { "NET_CAPABILITY_" }, value = {
            NET_CAPABILITY_MMS,
            NET_CAPABILITY_SUPL,
            NET_CAPABILITY_DUN,
            NET_CAPABILITY_FOTA,
            NET_CAPABILITY_IMS,
            NET_CAPABILITY_CBS,
            NET_CAPABILITY_WIFI_P2P,
            NET_CAPABILITY_IA,
            NET_CAPABILITY_RCS,
            NET_CAPABILITY_XCAP,
            NET_CAPABILITY_EIMS,
            NET_CAPABILITY_NOT_METERED,
            NET_CAPABILITY_INTERNET,
            NET_CAPABILITY_NOT_RESTRICTED,
            NET_CAPABILITY_TRUSTED,
            NET_CAPABILITY_NOT_VPN,
            NET_CAPABILITY_VALIDATED,
            NET_CAPABILITY_CAPTIVE_PORTAL,
            NET_CAPABILITY_NOT_ROAMING,
            NET_CAPABILITY_FOREGROUND,
            NET_CAPABILITY_NOT_CONGESTED,
            NET_CAPABILITY_NOT_SUSPENDED,
            NET_CAPABILITY_OEM_PAID,
            NET_CAPABILITY_MCX,
            NET_CAPABILITY_PARTIAL_CONNECTIVITY,
    })
    public @interface NetCapability { }

    /**
     * Indicates this is a network that has the ability to reach the
     * carrier's MMSC for sending and receiving MMS messages.
     */
    public static final int NET_CAPABILITY_MMS            = 0;

    /**
     * Indicates this is a network that has the ability to reach the carrier's
     * SUPL server, used to retrieve GPS information.
     */
    public static final int NET_CAPABILITY_SUPL           = 1;

    /**
     * Indicates this is a network that has the ability to reach the carrier's
     * DUN or tethering gateway.
     */
    public static final int NET_CAPABILITY_DUN            = 2;

    /**
     * Indicates this is a network that has the ability to reach the carrier's
     * FOTA portal, used for over the air updates.
     */
    public static final int NET_CAPABILITY_FOTA           = 3;

    /**
     * Indicates this is a network that has the ability to reach the carrier's
     * IMS servers, used for network registration and signaling.
     */
    public static final int NET_CAPABILITY_IMS            = 4;

    /**
     * Indicates this is a network that has the ability to reach the carrier's
     * CBS servers, used for carrier specific services.
     */
    public static final int NET_CAPABILITY_CBS            = 5;

    /**
     * Indicates this is a network that has the ability to reach a Wi-Fi direct
     * peer.
     */
    public static final int NET_CAPABILITY_WIFI_P2P       = 6;

    /**
     * Indicates this is a network that has the ability to reach a carrier's
     * Initial Attach servers.
     */
    public static final int NET_CAPABILITY_IA             = 7;

    /**
     * Indicates this is a network that has the ability to reach a carrier's
     * RCS servers, used for Rich Communication Services.
     */
    public static final int NET_CAPABILITY_RCS            = 8;

    /**
     * Indicates this is a network that has the ability to reach a carrier's
     * XCAP servers, used for configuration and control.
     */
    public static final int NET_CAPABILITY_XCAP           = 9;

    /**
     * Indicates this is a network that has the ability to reach a carrier's
     * Emergency IMS servers or other services, used for network signaling
     * during emergency calls.
     */
    public static final int NET_CAPABILITY_EIMS           = 10;

    /**
     * Indicates that this network is unmetered.
     */
    public static final int NET_CAPABILITY_NOT_METERED    = 11;

    /**
     * Indicates that this network should be able to reach the internet.
     */
    public static final int NET_CAPABILITY_INTERNET       = 12;

    /**
     * Indicates that this network is available for general use.  If this is not set
     * applications should not attempt to communicate on this network.  Note that this
     * is simply informative and not enforcement - enforcement is handled via other means.
     * Set by default.
     */
    public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;

    /**
     * Indicates that the user has indicated implicit trust of this network.  This
     * generally means it's a sim-selected carrier, a plugged in ethernet, a paired
     * BT device or a wifi the user asked to connect to.  Untrusted networks
     * are probably limited to unknown wifi AP.  Set by default.
     */
    public static final int NET_CAPABILITY_TRUSTED        = 14;

    /**
     * Indicates that this network is not a VPN.  This capability is set by default and should be
     * explicitly cleared for VPN networks.
     */
    public static final int NET_CAPABILITY_NOT_VPN        = 15;

    /**
     * Indicates that connectivity on this network was successfully validated. For example, for a
     * network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully
     * detected.
     */
    public static final int NET_CAPABILITY_VALIDATED      = 16;

    /**
     * Indicates that this network was found to have a captive portal in place last time it was
     * probed.
     */
    public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;

    /**
     * Indicates that this network is not roaming.
     */
    public static final int NET_CAPABILITY_NOT_ROAMING = 18;

    /**
     * Indicates that this network is available for use by apps, and not a network that is being
     * kept up in the background to facilitate fast network switching.
     */
    public static final int NET_CAPABILITY_FOREGROUND = 19;

    /**
     * Indicates that this network is not congested.
     * <p>
     * When a network is congested, applications should defer network traffic
     * that can be done at a later time, such as uploading analytics.
     */
    public static final int NET_CAPABILITY_NOT_CONGESTED = 20;

    /**
     * Indicates that this network is not currently suspended.
     * <p>
     * When a network is suspended, the network's IP addresses and any connections
     * established on the network remain valid, but the network is temporarily unable
     * to transfer data. This can happen, for example, if a cellular network experiences
     * a temporary loss of signal, such as when driving through a tunnel, etc.
     * A network with this capability is not suspended, so is expected to be able to
     * transfer data.
     */
    public static final int NET_CAPABILITY_NOT_SUSPENDED = 21;

    /**
     * Indicates that traffic that goes through this network is paid by oem. For example,
     * this network can be used by system apps to upload telemetry data.
     * @hide
     */
    @SystemApi
    public static final int NET_CAPABILITY_OEM_PAID = 22;

    /**
     * Indicates this is a network that has the ability to reach a carrier's Mission Critical
     * servers.
     */
    public static final int NET_CAPABILITY_MCX = 23;

    /**
     * Indicates that this network was tested to only provide partial connectivity.
     * @hide
     */
    @SystemApi
    public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24;

    private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_PARTIAL_CONNECTIVITY;

    /**
     * Network capabilities that are expected to be mutable, i.e., can change while a particular
     * network is connected.
     */
    private static final long MUTABLE_CAPABILITIES =
            // TRUSTED can change when user explicitly connects to an untrusted network in Settings.
            // http://b/18206275
            (1 << NET_CAPABILITY_TRUSTED)
            | (1 << NET_CAPABILITY_VALIDATED)
            | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
            | (1 << NET_CAPABILITY_NOT_ROAMING)
            | (1 << NET_CAPABILITY_FOREGROUND)
            | (1 << NET_CAPABILITY_NOT_CONGESTED)
            | (1 << NET_CAPABILITY_NOT_SUSPENDED)
            | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY);

    /**
     * Network capabilities that are not allowed in NetworkRequests. This exists because the
     * NetworkFactory / NetworkAgent model does not deal well with the situation where a
     * capability's presence cannot be known in advance. If such a capability is requested, then we
     * can get into a cycle where the NetworkFactory endlessly churns out NetworkAgents that then
     * get immediately torn down because they do not have the requested capability.
     */
    private static final long NON_REQUESTABLE_CAPABILITIES =
            MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_TRUSTED);

    /**
     * Capabilities that are set by default when the object is constructed.
     */
    private static final long DEFAULT_CAPABILITIES =
            (1 << NET_CAPABILITY_NOT_RESTRICTED) |
            (1 << NET_CAPABILITY_TRUSTED) |
            (1 << NET_CAPABILITY_NOT_VPN);

    /**
     * Capabilities that suggest that a network is restricted.
     * {@see #maybeMarkCapabilitiesRestricted}, {@see #FORCE_RESTRICTED_CAPABILITIES}
     */
    @VisibleForTesting
    /* package */ static final long RESTRICTED_CAPABILITIES =
            (1 << NET_CAPABILITY_CBS) |
            (1 << NET_CAPABILITY_DUN) |
            (1 << NET_CAPABILITY_EIMS) |
            (1 << NET_CAPABILITY_FOTA) |
            (1 << NET_CAPABILITY_IA) |
            (1 << NET_CAPABILITY_IMS) |
            (1 << NET_CAPABILITY_RCS) |
            (1 << NET_CAPABILITY_XCAP) |
            (1 << NET_CAPABILITY_MCX);

    /**
     * Capabilities that force network to be restricted.
     * {@see #maybeMarkCapabilitiesRestricted}.
     */
    private static final long FORCE_RESTRICTED_CAPABILITIES =
            (1 << NET_CAPABILITY_OEM_PAID);

    /**
     * Capabilities that suggest that a network is unrestricted.
     * {@see #maybeMarkCapabilitiesRestricted}.
     */
    @VisibleForTesting
    /* package */ static final long UNRESTRICTED_CAPABILITIES =
            (1 << NET_CAPABILITY_INTERNET) |
            (1 << NET_CAPABILITY_MMS) |
            (1 << NET_CAPABILITY_SUPL) |
            (1 << NET_CAPABILITY_WIFI_P2P);

    /**
     * Capabilities that are managed by ConnectivityService.
     */
    private static final long CONNECTIVITY_MANAGED_CAPABILITIES =
            (1 << NET_CAPABILITY_VALIDATED)
            | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
            | (1 << NET_CAPABILITY_FOREGROUND)
            | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY);

    /**
     * Adds the given capability to this {@code NetworkCapability} instance.
     * Multiple capabilities may be applied sequentially.  Note that when searching
     * for a network to satisfy a request, all capabilities requested must be satisfied.
     * <p>
     * If the given capability was previously added to the list of unwanted capabilities
     * then the capability will also be removed from the list of unwanted capabilities.
     *
     * @param capability the capability to be added.
     * @return This NetworkCapabilities instance, to facilitate chaining.
     * @hide
     */
    @UnsupportedAppUsage
    public @NonNull NetworkCapabilities addCapability(@NetCapability int capability) {
        checkValidCapability(capability);
        mNetworkCapabilities |= 1 << capability;
        mUnwantedNetworkCapabilities &= ~(1 << capability);  // remove from unwanted capability list
        return this;
    }

    /**
     * Adds the given capability to the list of unwanted capabilities of this
     * {@code NetworkCapability} instance.  Multiple unwanted capabilities may be applied
     * sequentially.  Note that when searching for a network to satisfy a request, the network
     * must not contain any capability from unwanted capability list.
     * <p>
     * If the capability was previously added to the list of required capabilities (for
     * example, it was there by default or added using {@link #addCapability(int)} method), then
     * it will be removed from the list of required capabilities as well.
     *
     * @see #addCapability(int)
     * @hide
     */
    public void addUnwantedCapability(@NetCapability int capability) {
        checkValidCapability(capability);
        mUnwantedNetworkCapabilities |= 1 << capability;
        mNetworkCapabilities &= ~(1 << capability);  // remove from requested capabilities
    }

    /**
     * Removes (if found) the given capability from this {@code NetworkCapability} instance.
     * <p>
     * Note that this method removes capabilities that were added via {@link #addCapability(int)},
     * {@link #addUnwantedCapability(int)} or {@link #setCapabilities(int[], int[])} .
     *
     * @param capability the capability to be removed.
     * @return This NetworkCapabilities instance, to facilitate chaining.
     * @hide
     */
    @UnsupportedAppUsage
    public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
        checkValidCapability(capability);
        final long mask = ~(1 << capability);
        mNetworkCapabilities &= mask;
        mUnwantedNetworkCapabilities &= mask;
        return this;
    }

    /**
     * Sets (or clears) the given capability on this {@link NetworkCapabilities}
     * instance.
     *
     * @hide
     */
    public @NonNull NetworkCapabilities setCapability(@NetCapability int capability,
            boolean value) {
        if (value) {
            addCapability(capability);
        } else {
            removeCapability(capability);
        }
        return this;
    }

    /**
     * Gets all the capabilities set on this {@code NetworkCapability} instance.
     *
     * @return an array of capability values for this instance.
     * @hide
     */
    @TestApi
    public @NetCapability int[] getCapabilities() {
        return BitUtils.unpackBits(mNetworkCapabilities);
    }

    /**
     * Gets all the unwanted capabilities set on this {@code NetworkCapability} instance.
     *
     * @return an array of unwanted capability values for this instance.
     * @hide
     */
    public @NetCapability int[] getUnwantedCapabilities() {
        return BitUtils.unpackBits(mUnwantedNetworkCapabilities);
    }


    /**
     * Sets all the capabilities set on this {@code NetworkCapability} instance.
     * This overwrites any existing capabilities.
     *
     * @hide
     */
    public void setCapabilities(@NetCapability int[] capabilities,
            @NetCapability int[] unwantedCapabilities) {
        mNetworkCapabilities = BitUtils.packBits(capabilities);
        mUnwantedNetworkCapabilities = BitUtils.packBits(unwantedCapabilities);
    }

    /**
     * @deprecated use {@link #setCapabilities(int[], int[])}
     * @hide
     */
    @Deprecated
    public void setCapabilities(@NetCapability int[] capabilities) {
        setCapabilities(capabilities, new int[] {});
    }

    /**
     * Tests for the presence of a capability on this instance.
     *
     * @param capability the capabilities to be tested for.
     * @return {@code true} if set on this instance.
     */
    public boolean hasCapability(@NetCapability int capability) {
        return isValidCapability(capability)
                && ((mNetworkCapabilities & (1 << capability)) != 0);
    }

    /** @hide */
    public boolean hasUnwantedCapability(@NetCapability int capability) {
        return isValidCapability(capability)
                && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
    }

    /**
     * Check if this NetworkCapabilities has system managed capabilities or not.
     * @hide
     */
    public boolean hasConnectivityManagedCapability() {
        return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
    }

    /** Note this method may result in having the same capability in wanted and unwanted lists. */
    private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
        this.mNetworkCapabilities |= nc.mNetworkCapabilities;
        this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities;
    }

    /**
     * Convenience function that returns a human-readable description of the first mutable
     * capability we find. Used to present an error message to apps that request mutable
     * capabilities.
     *
     * @hide
     */
    public @Nullable String describeFirstNonRequestableCapability() {
        final long nonRequestable = (mNetworkCapabilities | mUnwantedNetworkCapabilities)
                & NON_REQUESTABLE_CAPABILITIES;

        if (nonRequestable != 0) {
            return capabilityNameOf(BitUtils.unpackBits(nonRequestable)[0]);
        }
        if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth";
        if (hasSignalStrength()) return "signalStrength";
        return null;
    }

    private boolean satisfiedByNetCapabilities(@NonNull NetworkCapabilities nc,
            boolean onlyImmutable) {
        long requestedCapabilities = mNetworkCapabilities;
        long requestedUnwantedCapabilities = mUnwantedNetworkCapabilities;
        long providedCapabilities = nc.mNetworkCapabilities;

        if (onlyImmutable) {
            requestedCapabilities &= ~MUTABLE_CAPABILITIES;
            requestedUnwantedCapabilities &= ~MUTABLE_CAPABILITIES;
        }
        return ((providedCapabilities & requestedCapabilities) == requestedCapabilities)
                && ((requestedUnwantedCapabilities & providedCapabilities) == 0);
    }

    /** @hide */
    public boolean equalsNetCapabilities(@NonNull NetworkCapabilities nc) {
        return (nc.mNetworkCapabilities == this.mNetworkCapabilities)
                && (nc.mUnwantedNetworkCapabilities == this.mUnwantedNetworkCapabilities);
    }

    private boolean equalsNetCapabilitiesRequestable(@NonNull NetworkCapabilities that) {
        return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
                (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES))
                && ((this.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
                (that.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
    }

    /**
     * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are
     * typically provided by restricted networks.
     *
     * TODO: consider:
     * - Renaming it to guessRestrictedCapability and make it set the
     *   restricted capability bit in addition to clearing it.
     * @hide
     */
    public void maybeMarkCapabilitiesRestricted() {
        // Check if we have any capability that forces the network to be restricted.
        final boolean forceRestrictedCapability =
                (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0;

        // Verify there aren't any unrestricted capabilities.  If there are we say
        // the whole thing is unrestricted unless it is forced to be restricted.
        final boolean hasUnrestrictedCapabilities =
                (mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0;

        // Must have at least some restricted capabilities.
        final boolean hasRestrictedCapabilities =
                (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0;

        if (forceRestrictedCapability
                || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities)) {
            removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
        }
    }

    /**
     * Representing the transport type.  Apps should generally not care about transport.  A
     * request for a fast internet connection could be satisfied by a number of different
     * transports.  If any are specified here it will be satisfied a Network that matches
     * any of them.  If a caller doesn't care about the transport it should not specify any.
     */
    private long mTransportTypes;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = { "TRANSPORT_" }, value = {
            TRANSPORT_CELLULAR,
            TRANSPORT_WIFI,
            TRANSPORT_BLUETOOTH,
            TRANSPORT_ETHERNET,
            TRANSPORT_VPN,
            TRANSPORT_WIFI_AWARE,
            TRANSPORT_LOWPAN,
            TRANSPORT_TEST,
    })
    public @interface Transport { }

    /**
     * Indicates this network uses a Cellular transport.
     */
    public static final int TRANSPORT_CELLULAR = 0;

    /**
     * Indicates this network uses a Wi-Fi transport.
     */
    public static final int TRANSPORT_WIFI = 1;

    /**
     * Indicates this network uses a Bluetooth transport.
     */
    public static final int TRANSPORT_BLUETOOTH = 2;

    /**
     * Indicates this network uses an Ethernet transport.
     */
    public static final int TRANSPORT_ETHERNET = 3;

    /**
     * Indicates this network uses a VPN transport.
     */
    public static final int TRANSPORT_VPN = 4;

    /**
     * Indicates this network uses a Wi-Fi Aware transport.
     */
    public static final int TRANSPORT_WIFI_AWARE = 5;

    /**
     * Indicates this network uses a LoWPAN transport.
     */
    public static final int TRANSPORT_LOWPAN = 6;

    /**
     * Indicates this network uses a Test-only virtual interface as a transport.
     *
     * @hide
     */
    @TestApi
    public static final int TRANSPORT_TEST = 7;

    /** @hide */
    public static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
    /** @hide */
    public static final int MAX_TRANSPORT = TRANSPORT_TEST;

    /** @hide */
    public static boolean isValidTransport(@Transport int transportType) {
        return (MIN_TRANSPORT <= transportType) && (transportType <= MAX_TRANSPORT);
    }

    private static final String[] TRANSPORT_NAMES = {
        "CELLULAR",
        "WIFI",
        "BLUETOOTH",
        "ETHERNET",
        "VPN",
        "WIFI_AWARE",
        "LOWPAN",
        "TEST"
    };

    /**
     * Adds the given transport type to this {@code NetworkCapability} instance.
     * Multiple transports may be applied sequentially.  Note that when searching
     * for a network to satisfy a request, any listed in the request will satisfy the request.
     * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
     * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
     * to be selected.  This is logically different than
     * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
     *
     * @param transportType the transport type to be added.
     * @return This NetworkCapabilities instance, to facilitate chaining.
     * @hide
     */
    @UnsupportedAppUsage
    public @NonNull NetworkCapabilities addTransportType(@Transport int transportType) {
        checkValidTransportType(transportType);
        mTransportTypes |= 1 << transportType;
        setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
        return this;
    }

    /**
     * Removes (if found) the given transport from this {@code NetworkCapability} instance.
     *
     * @param transportType the transport type to be removed.
     * @return This NetworkCapabilities instance, to facilitate chaining.
     * @hide
     */
    public @NonNull NetworkCapabilities removeTransportType(@Transport int transportType) {
        checkValidTransportType(transportType);
        mTransportTypes &= ~(1 << transportType);
        setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
        return this;
    }

    /**
     * Sets (or clears) the given transport on this {@link NetworkCapabilities}
     * instance.
     *
     * @hide
     */
    public @NonNull NetworkCapabilities setTransportType(@Transport int transportType,
            boolean value) {
        if (value) {
            addTransportType(transportType);
        } else {
            removeTransportType(transportType);
        }
        return this;
    }

    /**
     * Gets all the transports set on this {@code NetworkCapability} instance.
     *
     * @return an array of transport type values for this instance.
     * @hide
     */
    @TestApi
    @SystemApi
    @NonNull public @Transport int[] getTransportTypes() {
        return BitUtils.unpackBits(mTransportTypes);
    }

    /**
     * Sets all the transports set on this {@code NetworkCapability} instance.
     * This overwrites any existing transports.
     *
     * @hide
     */
    public void setTransportTypes(@Transport int[] transportTypes) {
        mTransportTypes = BitUtils.packBits(transportTypes);
    }

    /**
     * Tests for the presence of a transport on this instance.
     *
     * @param transportType the transport type to be tested for.
     * @return {@code true} if set on this instance.
     */
    public boolean hasTransport(@Transport int transportType) {
        return isValidTransport(transportType) && ((mTransportTypes & (1 << transportType)) != 0);
    }

    private void combineTransportTypes(NetworkCapabilities nc) {
        this.mTransportTypes |= nc.mTransportTypes;
    }

    private boolean satisfiedByTransportTypes(NetworkCapabilities nc) {
        return ((this.mTransportTypes == 0) ||
                ((this.mTransportTypes & nc.mTransportTypes) != 0));
    }

    /** @hide */
    public boolean equalsTransportTypes(NetworkCapabilities nc) {
        return (nc.mTransportTypes == this.mTransportTypes);
    }

    /**
     * UID of the app that manages this network, or INVALID_UID if none/unknown.
     *
     * This field keeps track of the UID of the app that created this network and is in charge
     * of managing it. In the practice, it is used to store the UID of VPN apps so it is named
     * accordingly, but it may be renamed if other mechanisms are offered for third party apps
     * to create networks.
     *
     * Because this field is only used in the services side (and to avoid apps being able to
     * set this to whatever they want), this field is not parcelled and will not be conserved
     * across the IPC boundary.
     * @hide
     */
    private int mEstablishingVpnAppUid = INVALID_UID;

    /**
     * Set the UID of the managing app.
     * @hide
     */
    public void setEstablishingVpnAppUid(final int uid) {
        mEstablishingVpnAppUid = uid;
    }

    /** @hide */
    public int getEstablishingVpnAppUid() {
        return mEstablishingVpnAppUid;
    }

    /**
     * Value indicating that link bandwidth is unspecified.
     * @hide
     */
    public static final int LINK_BANDWIDTH_UNSPECIFIED = 0;

    /**
     * Passive link bandwidth.  This is a rough guide of the expected peak bandwidth
     * for the first hop on the given transport.  It is not measured, but may take into account
     * link parameters (Radio technology, allocated channels, etc).
     */
    private int mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
    private int mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;

    /**
     * Sets the upstream bandwidth for this network in Kbps.  This always only refers to
     * the estimated first hop transport bandwidth.
     * <p>
     * Note that when used to request a network, this specifies the minimum acceptable.
     * When received as the state of an existing network this specifies the typical
     * first hop bandwidth expected.  This is never measured, but rather is inferred
     * from technology type and other link parameters.  It could be used to differentiate
     * between very slow 1xRTT cellular links and other faster networks or even between
     * 802.11b vs 802.11AC wifi technologies.  It should not be used to differentiate between
     * fast backhauls and slow backhauls.
     *
     * @param upKbps the estimated first hop upstream (device to network) bandwidth.
     * @hide
     */
    public @NonNull NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) {
        mLinkUpBandwidthKbps = upKbps;
        return this;
    }

    /**
     * Retrieves the upstream bandwidth for this network in Kbps.  This always only refers to
     * the estimated first hop transport bandwidth.
     *
     * @return The estimated first hop upstream (device to network) bandwidth.
     */
    public int getLinkUpstreamBandwidthKbps() {
        return mLinkUpBandwidthKbps;
    }

    /**
     * Sets the downstream bandwidth for this network in Kbps.  This always only refers to
     * the estimated first hop transport bandwidth.
     * <p>
     * Note that when used to request a network, this specifies the minimum acceptable.
     * When received as the state of an existing network this specifies the typical
     * first hop bandwidth expected.  This is never measured, but rather is inferred
     * from technology type and other link parameters.  It could be used to differentiate
     * between very slow 1xRTT cellular links and other faster networks or even between
     * 802.11b vs 802.11AC wifi technologies.  It should not be used to differentiate between
     * fast backhauls and slow backhauls.
     *
     * @param downKbps the estimated first hop downstream (network to device) bandwidth.
     * @hide
     */
    public @NonNull NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) {
        mLinkDownBandwidthKbps = downKbps;
        return this;
    }

    /**
     * Retrieves the downstream bandwidth for this network in Kbps.  This always only refers to
     * the estimated first hop transport bandwidth.
     *
     * @return The estimated first hop downstream (network to device) bandwidth.
     */
    public int getLinkDownstreamBandwidthKbps() {
        return mLinkDownBandwidthKbps;
    }

    private void combineLinkBandwidths(NetworkCapabilities nc) {
        this.mLinkUpBandwidthKbps =
                Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps);
        this.mLinkDownBandwidthKbps =
                Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps);
    }
    private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) {
        return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps ||
                this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps);
    }
    private boolean equalsLinkBandwidths(NetworkCapabilities nc) {
        return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps &&
                this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps);
    }
    /** @hide */
    public static int minBandwidth(int a, int b) {
        if (a == LINK_BANDWIDTH_UNSPECIFIED)  {
            return b;
        } else if (b == LINK_BANDWIDTH_UNSPECIFIED) {
            return a;
        } else {
            return Math.min(a, b);
        }
    }
    /** @hide */
    public static int maxBandwidth(int a, int b) {
        return Math.max(a, b);
    }

    private NetworkSpecifier mNetworkSpecifier = null;
    private TransportInfo mTransportInfo = null;

    /**
     * Sets the optional bearer specific network specifier.
     * This has no meaning if a single transport is also not specified, so calling
     * this without a single transport set will generate an exception, as will
     * subsequently adding or removing transports after this is set.
     * </p>
     *
     * @param networkSpecifier A concrete, parcelable framework class that extends
     *                         NetworkSpecifier.
     * @return This NetworkCapabilities instance, to facilitate chaining.
     * @hide
     */
    public @NonNull NetworkCapabilities setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
        if (networkSpecifier != null && Long.bitCount(mTransportTypes) != 1) {
            throw new IllegalStateException("Must have a single transport specified to use " +
                    "setNetworkSpecifier");
        }

        mNetworkSpecifier = networkSpecifier;

        return this;
    }

    /**
     * Sets the optional transport specific information.
     *
     * @param transportInfo A concrete, parcelable framework class that extends
     * {@link TransportInfo}.
     * @return This NetworkCapabilities instance, to facilitate chaining.
     * @hide
     */
    public @NonNull NetworkCapabilities setTransportInfo(TransportInfo transportInfo) {
        mTransportInfo = transportInfo;
        return this;
    }

    /**
     * Gets the optional bearer specific network specifier. May be {@code null} if not set.
     *
     * @return The optional {@link NetworkSpecifier} specifying the bearer specific network
     *         specifier or {@code null}. See {@link #setNetworkSpecifier}.
     * @hide
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    public @Nullable NetworkSpecifier getNetworkSpecifier() {
        return mNetworkSpecifier;
    }

    /**
     * Returns a transport-specific information container. The application may cast this
     * container to a concrete sub-class based on its knowledge of the network request. The
     * application should be able to deal with a {@code null} return value or an invalid case,
     * e.g. use {@code instanceof} operator to verify expected type.
     *
     * @return A concrete implementation of the {@link TransportInfo} class or null if not
     * available for the network.
     */
    @Nullable public TransportInfo getTransportInfo() {
        return mTransportInfo;
    }

    private void combineSpecifiers(NetworkCapabilities nc) {
        if (mNetworkSpecifier != null && !mNetworkSpecifier.equals(nc.mNetworkSpecifier)) {
            throw new IllegalStateException("Can't combine two networkSpecifiers");
        }
        setNetworkSpecifier(nc.mNetworkSpecifier);
    }

    private boolean satisfiedBySpecifier(NetworkCapabilities nc) {
        return mNetworkSpecifier == null || mNetworkSpecifier.satisfiedBy(nc.mNetworkSpecifier)
                || nc.mNetworkSpecifier instanceof MatchAllNetworkSpecifier;
    }

    private boolean equalsSpecifier(NetworkCapabilities nc) {
        return Objects.equals(mNetworkSpecifier, nc.mNetworkSpecifier);
    }

    private void combineTransportInfos(NetworkCapabilities nc) {
        if (mTransportInfo != null && !mTransportInfo.equals(nc.mTransportInfo)) {
            throw new IllegalStateException("Can't combine two TransportInfos");
        }
        setTransportInfo(nc.mTransportInfo);
    }

    private boolean equalsTransportInfo(NetworkCapabilities nc) {
        return Objects.equals(mTransportInfo, nc.mTransportInfo);
    }

    /**
     * Magic value that indicates no signal strength provided. A request specifying this value is
     * always satisfied.
     */
    public static final int SIGNAL_STRENGTH_UNSPECIFIED = Integer.MIN_VALUE;

    /**
     * Signal strength. This is a signed integer, and higher values indicate better signal.
     * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;

    /**
     * Sets the signal strength. This is a signed integer, with higher values indicating a stronger
     * signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same RSSI units
     * reported by wifi code.
     * <p>
     * Note that when used to register a network callback, this specifies the minimum acceptable
     * signal strength. When received as the state of an existing network it specifies the current
     * value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means no value when received and has no
     * effect when requesting a callback.
     *
     * @param signalStrength the bearer-specific signal strength.
     * @hide
     */
    @UnsupportedAppUsage
    public @NonNull NetworkCapabilities setSignalStrength(int signalStrength) {
        mSignalStrength = signalStrength;
        return this;
    }

    /**
     * Returns {@code true} if this object specifies a signal strength.
     *
     * @hide
     */
    @UnsupportedAppUsage
    public boolean hasSignalStrength() {
        return mSignalStrength > SIGNAL_STRENGTH_UNSPECIFIED;
    }

    /**
     * Retrieves the signal strength.
     *
     * @return The bearer-specific signal strength.
     */
    public int getSignalStrength() {
        return mSignalStrength;
    }

    private void combineSignalStrength(NetworkCapabilities nc) {
        this.mSignalStrength = Math.max(this.mSignalStrength, nc.mSignalStrength);
    }

    private boolean satisfiedBySignalStrength(NetworkCapabilities nc) {
        return this.mSignalStrength <= nc.mSignalStrength;
    }

    private boolean equalsSignalStrength(NetworkCapabilities nc) {
        return this.mSignalStrength == nc.mSignalStrength;
    }

    /**
     * List of UIDs this network applies to. No restriction if null.
     * <p>
     * For networks, mUids represent the list of network this applies to, and null means this
     * network applies to all UIDs.
     * For requests, mUids is the list of UIDs this network MUST apply to to match ; ALL UIDs
     * must be included in a network so that they match. As an exception to the general rule,
     * a null mUids field for requests mean "no requirements" rather than what the general rule
     * would suggest ("must apply to all UIDs") : this is because this has shown to be what users
     * of this API expect in practice. A network that must match all UIDs can still be
     * expressed with a set ranging the entire set of possible UIDs.
     * <p>
     * mUids is typically (and at this time, only) used by VPN. This network is only available to
     * the UIDs in this list, and it is their default network. Apps in this list that wish to
     * bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this
     * member is null, then the network is not restricted by app UID. If it's an empty list, then
     * it means nobody can use it.
     * As a special exception, the app managing this network (as identified by its UID stored in
     * mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in
     * satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong>
     * to the app that manages it as determined by #appliesToUid.
     * <p>
     * Please note that in principle a single app can be associated with multiple UIDs because
     * each app will have a different UID when it's run as a different (macro-)user. A single
     * macro user can only have a single active VPN app at any given time however.
     * <p>
     * Also please be aware this class does not try to enforce any normalization on this. Callers
     * can only alter the UIDs by setting them wholesale : this class does not provide any utility
     * to add or remove individual UIDs or ranges. If callers have any normalization needs on
     * their own (like requiring sortedness or no overlap) they need to enforce it
     * themselves. Some of the internal methods also assume this is normalized as in no adjacent
     * or overlapping ranges are present.
     *
     * @hide
     */
    private ArraySet<UidRange> mUids = null;

    /**
     * Convenience method to set the UIDs this network applies to to a single UID.
     * @hide
     */
    public @NonNull NetworkCapabilities setSingleUid(int uid) {
        final ArraySet<UidRange> identity = new ArraySet<>(1);
        identity.add(new UidRange(uid, uid));
        setUids(identity);
        return this;
    }

    /**
     * Set the list of UIDs this network applies to.
     * This makes a copy of the set so that callers can't modify it after the call.
     * @hide
     */
    public @NonNull NetworkCapabilities setUids(Set<UidRange> uids) {
        if (null == uids) {
            mUids = null;
        } else {
            mUids = new ArraySet<>(uids);
        }
        return this;
    }

    /**
     * Get the list of UIDs this network applies to.
     * This returns a copy of the set so that callers can't modify the original object.
     * @hide
     */
    public @Nullable Set<UidRange> getUids() {
        return null == mUids ? null : new ArraySet<>(mUids);
    }

    /**
     * Test whether this network applies to this UID.
     * @hide
     */
    public boolean appliesToUid(int uid) {
        if (null == mUids) return true;
        for (UidRange range : mUids) {
            if (range.contains(uid)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Tests if the set of UIDs that this network applies to is the same as the passed network.
     * <p>
     * This test only checks whether equal range objects are in both sets. It will
     * return false if the ranges are not exactly the same, even if the covered UIDs
     * are for an equivalent result.
     * <p>
     * Note that this method is not very optimized, which is fine as long as it's not used very
     * often.
     * <p>
     * nc is assumed nonnull.
     *
     * @hide
     */
    @VisibleForTesting
    public boolean equalsUids(@NonNull NetworkCapabilities nc) {
        Set<UidRange> comparedUids = nc.mUids;
        if (null == comparedUids) return null == mUids;
        if (null == mUids) return false;
        // Make a copy so it can be mutated to check that all ranges in mUids
        // also are in uids.
        final Set<UidRange> uids = new ArraySet<>(mUids);
        for (UidRange range : comparedUids) {
            if (!uids.contains(range)) {
                return false;
            }
            uids.remove(range);
        }
        return uids.isEmpty();
    }

    /**
     * Test whether the passed NetworkCapabilities satisfies the UIDs this capabilities require.
     *
     * This method is called on the NetworkCapabilities embedded in a request with the
     * capabilities of an available network. It checks whether all the UIDs from this listen
     * (representing the UIDs that must have access to the network) are satisfied by the UIDs
     * in the passed nc (representing the UIDs that this network is available to).
     * <p>
     * As a special exception, the UID that created the passed network (as represented by its
     * mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN
     * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app
     * can see its own network when it listens for it.
     * <p>
     * nc is assumed nonnull. Else, NPE.
     * @see #appliesToUid
     * @hide
     */
    public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) {
        if (null == nc.mUids || null == mUids) return true; // The network satisfies everything.
        for (UidRange requiredRange : mUids) {
            if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
            if (!nc.appliesToUidRange(requiredRange)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Returns whether this network applies to the passed ranges.
     * This assumes that to apply, the passed range has to be entirely contained
     * within one of the ranges this network applies to. If the ranges are not normalized,
     * this method may return false even though all required UIDs are covered because no
     * single range contained them all.
     * @hide
     */
    @VisibleForTesting
    public boolean appliesToUidRange(@Nullable UidRange requiredRange) {
        if (null == mUids) return true;
        for (UidRange uidRange : mUids) {
            if (uidRange.containsRange(requiredRange)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Combine the UIDs this network currently applies to with the UIDs the passed
     * NetworkCapabilities apply to.
     * nc is assumed nonnull.
     */
    private void combineUids(@NonNull NetworkCapabilities nc) {
        if (null == nc.mUids || null == mUids) {
            mUids = null;
            return;
        }
        mUids.addAll(nc.mUids);
    }


    /**
     * The SSID of the network, or null if not applicable or unknown.
     * <p>
     * This is filled in by wifi code.
     * @hide
     */
    private String mSSID;

    /**
     * Sets the SSID of this network.
     * @hide
     */
    public @NonNull NetworkCapabilities setSSID(@Nullable String ssid) {
        mSSID = ssid;
        return this;
    }

    /**
     * Gets the SSID of this network, or null if none or unknown.
     * @hide
     */
    public @Nullable String getSSID() {
        return mSSID;
    }

    /**
     * Tests if the SSID of this network is the same as the SSID of the passed network.
     * @hide
     */
    public boolean equalsSSID(@NonNull NetworkCapabilities nc) {
        return Objects.equals(mSSID, nc.mSSID);
    }

    /**
     * Check if the SSID requirements of this object are matched by the passed object.
     * @hide
     */
    public boolean satisfiedBySSID(@NonNull NetworkCapabilities nc) {
        return mSSID == null || mSSID.equals(nc.mSSID);
    }

    /**
     * Combine SSIDs of the capabilities.
     * <p>
     * This is only legal if either the SSID of this object is null, or both SSIDs are
     * equal.
     * @hide
     */
    private void combineSSIDs(@NonNull NetworkCapabilities nc) {
        if (mSSID != null && !mSSID.equals(nc.mSSID)) {
            throw new IllegalStateException("Can't combine two SSIDs");
        }
        setSSID(nc.mSSID);
    }

    /**
     * Combine a set of Capabilities to this one.  Useful for coming up with the complete set.
     * <p>
     * Note that this method may break an invariant of having a particular capability in either
     * wanted or unwanted lists but never in both.  Requests that have the same capability in
     * both lists will never be satisfied.
     * @hide
     */
    public void combineCapabilities(@NonNull NetworkCapabilities nc) {
        combineNetCapabilities(nc);
        combineTransportTypes(nc);
        combineLinkBandwidths(nc);
        combineSpecifiers(nc);
        combineTransportInfos(nc);
        combineSignalStrength(nc);
        combineUids(nc);
        combineSSIDs(nc);
    }

    /**
     * Check if our requirements are satisfied by the given {@code NetworkCapabilities}.
     *
     * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements.
     * @param onlyImmutable if {@code true}, do not consider mutable requirements such as link
     *         bandwidth, signal strength, or validation / captive portal status.
     *
     * @hide
     */
    private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
        return (nc != null
                && satisfiedByNetCapabilities(nc, onlyImmutable)
                && satisfiedByTransportTypes(nc)
                && (onlyImmutable || satisfiedByLinkBandwidths(nc))
                && satisfiedBySpecifier(nc)
                && (onlyImmutable || satisfiedBySignalStrength(nc))
                && (onlyImmutable || satisfiedByUids(nc))
                && (onlyImmutable || satisfiedBySSID(nc)));
    }

    /**
     * Check if our requirements are satisfied by the given {@code NetworkCapabilities}.
     *
     * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements.
     *
     * @hide
     */
    @TestApi
    @SystemApi
    public boolean satisfiedByNetworkCapabilities(@Nullable NetworkCapabilities nc) {
        return satisfiedByNetworkCapabilities(nc, false);
    }

    /**
     * Check if our immutable requirements are satisfied by the given {@code NetworkCapabilities}.
     *
     * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements.
     *
     * @hide
     */
    public boolean satisfiedByImmutableNetworkCapabilities(@Nullable NetworkCapabilities nc) {
        return satisfiedByNetworkCapabilities(nc, true);
    }

    /**
     * Checks that our immutable capabilities are the same as those of the given
     * {@code NetworkCapabilities} and return a String describing any difference.
     * The returned String is empty if there is no difference.
     *
     * @hide
     */
    public String describeImmutableDifferences(@Nullable NetworkCapabilities that) {
        if (that == null) {
            return "other NetworkCapabilities was null";
        }

        StringJoiner joiner = new StringJoiner(", ");

        // Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103
        // TODO: properly support NOT_METERED as a mutable and requestable capability.
        final long mask = ~MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_NOT_METERED);
        long oldImmutableCapabilities = this.mNetworkCapabilities & mask;
        long newImmutableCapabilities = that.mNetworkCapabilities & mask;
        if (oldImmutableCapabilities != newImmutableCapabilities) {
            String before = capabilityNamesOf(BitUtils.unpackBits(oldImmutableCapabilities));
            String after = capabilityNamesOf(BitUtils.unpackBits(newImmutableCapabilities));
            joiner.add(String.format("immutable capabilities changed: %s -> %s", before, after));
        }

        if (!equalsSpecifier(that)) {
            NetworkSpecifier before = this.getNetworkSpecifier();
            NetworkSpecifier after = that.getNetworkSpecifier();
            joiner.add(String.format("specifier changed: %s -> %s", before, after));
        }

        if (!equalsTransportTypes(that)) {
            String before = transportNamesOf(this.getTransportTypes());
            String after = transportNamesOf(that.getTransportTypes());
            joiner.add(String.format("transports changed: %s -> %s", before, after));
        }

        return joiner.toString();
    }

    /**
     * Checks that our requestable capabilities are the same as those of the given
     * {@code NetworkCapabilities}.
     *
     * @hide
     */
    public boolean equalRequestableCapabilities(@Nullable NetworkCapabilities nc) {
        if (nc == null) return false;
        return (equalsNetCapabilitiesRequestable(nc) &&
                equalsTransportTypes(nc) &&
                equalsSpecifier(nc));
    }

    @Override
    public boolean equals(@Nullable Object obj) {
        if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
        NetworkCapabilities that = (NetworkCapabilities) obj;
        return (equalsNetCapabilities(that)
                && equalsTransportTypes(that)
                && equalsLinkBandwidths(that)
                && equalsSignalStrength(that)
                && equalsSpecifier(that)
                && equalsTransportInfo(that)
                && equalsUids(that)
                && equalsSSID(that));
    }

    @Override
    public int hashCode() {
        return (int) (mNetworkCapabilities & 0xFFFFFFFF)
                + ((int) (mNetworkCapabilities >> 32) * 3)
                + ((int) (mUnwantedNetworkCapabilities & 0xFFFFFFFF) * 5)
                + ((int) (mUnwantedNetworkCapabilities >> 32) * 7)
                + ((int) (mTransportTypes & 0xFFFFFFFF) * 11)
                + ((int) (mTransportTypes >> 32) * 13)
                + (mLinkUpBandwidthKbps * 17)
                + (mLinkDownBandwidthKbps * 19)
                + Objects.hashCode(mNetworkSpecifier) * 23
                + (mSignalStrength * 29)
                + Objects.hashCode(mUids) * 31
                + Objects.hashCode(mSSID) * 37
                + Objects.hashCode(mTransportInfo) * 41;
    }

    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(mNetworkCapabilities);
        dest.writeLong(mUnwantedNetworkCapabilities);
        dest.writeLong(mTransportTypes);
        dest.writeInt(mLinkUpBandwidthKbps);
        dest.writeInt(mLinkDownBandwidthKbps);
        dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
        dest.writeParcelable((Parcelable) mTransportInfo, flags);
        dest.writeInt(mSignalStrength);
        dest.writeArraySet(mUids);
        dest.writeString(mSSID);
    }

    public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
        new Creator<NetworkCapabilities>() {
            @Override
            public NetworkCapabilities createFromParcel(Parcel in) {
                NetworkCapabilities netCap = new NetworkCapabilities();

                netCap.mNetworkCapabilities = in.readLong();
                netCap.mUnwantedNetworkCapabilities = in.readLong();
                netCap.mTransportTypes = in.readLong();
                netCap.mLinkUpBandwidthKbps = in.readInt();
                netCap.mLinkDownBandwidthKbps = in.readInt();
                netCap.mNetworkSpecifier = in.readParcelable(null);
                netCap.mTransportInfo = in.readParcelable(null);
                netCap.mSignalStrength = in.readInt();
                netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
                        null /* ClassLoader, null for default */);
                netCap.mSSID = in.readString();
                return netCap;
            }
            @Override
            public NetworkCapabilities[] newArray(int size) {
                return new NetworkCapabilities[size];
            }
        };

    @Override
    public @NonNull String toString() {
        final StringBuilder sb = new StringBuilder("[");
        if (0 != mTransportTypes) {
            sb.append(" Transports: ");
            appendStringRepresentationOfBitMaskToStringBuilder(sb, mTransportTypes,
                    NetworkCapabilities::transportNameOf, "|");
        }
        if (0 != mNetworkCapabilities) {
            sb.append(" Capabilities: ");
            appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities,
                    NetworkCapabilities::capabilityNameOf, "&");
        }
        if (0 != mUnwantedNetworkCapabilities) {
            sb.append(" Unwanted: ");
            appendStringRepresentationOfBitMaskToStringBuilder(sb, mUnwantedNetworkCapabilities,
                    NetworkCapabilities::capabilityNameOf, "&");
        }
        if (mLinkUpBandwidthKbps > 0) {
            sb.append(" LinkUpBandwidth>=").append(mLinkUpBandwidthKbps).append("Kbps");
        }
        if (mLinkDownBandwidthKbps > 0) {
            sb.append(" LinkDnBandwidth>=").append(mLinkDownBandwidthKbps).append("Kbps");
        }
        if (mNetworkSpecifier != null) {
            sb.append(" Specifier: <").append(mNetworkSpecifier).append(">");
        }
        if (mTransportInfo != null) {
            sb.append(" TransportInfo: <").append(mTransportInfo).append(">");
        }
        if (hasSignalStrength()) {
            sb.append(" SignalStrength: ").append(mSignalStrength);
        }

        if (null != mUids) {
            if ((1 == mUids.size()) && (mUids.valueAt(0).count() == 1)) {
                sb.append(" Uid: ").append(mUids.valueAt(0).start);
            } else {
                sb.append(" Uids: <").append(mUids).append(">");
            }
        }
        if (mEstablishingVpnAppUid != INVALID_UID) {
            sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid);
        }

        if (null != mSSID) {
            sb.append(" SSID: ").append(mSSID);
        }

        sb.append("]");
        return sb.toString();
    }


    private interface NameOf {
        String nameOf(int value);
    }
    /**
     * @hide
     */
    public static void appendStringRepresentationOfBitMaskToStringBuilder(@NonNull StringBuilder sb,
            long bitMask, @NonNull NameOf nameFetcher, @NonNull String separator) {
        int bitPos = 0;
        boolean firstElementAdded = false;
        while (bitMask != 0) {
            if ((bitMask & 1) != 0) {
                if (firstElementAdded) {
                    sb.append(separator);
                } else {
                    firstElementAdded = true;
                }
                sb.append(nameFetcher.nameOf(bitPos));
            }
            bitMask >>= 1;
            ++bitPos;
        }
    }

    /** @hide */
    public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) {
        final long token = proto.start(fieldId);

        for (int transport : getTransportTypes()) {
            proto.write(NetworkCapabilitiesProto.TRANSPORTS, transport);
        }

        for (int capability : getCapabilities()) {
            proto.write(NetworkCapabilitiesProto.CAPABILITIES, capability);
        }

        proto.write(NetworkCapabilitiesProto.LINK_UP_BANDWIDTH_KBPS, mLinkUpBandwidthKbps);
        proto.write(NetworkCapabilitiesProto.LINK_DOWN_BANDWIDTH_KBPS, mLinkDownBandwidthKbps);

        if (mNetworkSpecifier != null) {
            proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString());
        }
        if (mTransportInfo != null) {
            // TODO b/120653863: write transport-specific info to proto?
        }

        proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength());
        proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength);

        proto.end(token);
    }

    /**
     * @hide
     */
    public static @NonNull String capabilityNamesOf(@Nullable @NetCapability int[] capabilities) {
        StringJoiner joiner = new StringJoiner("|");
        if (capabilities != null) {
            for (int c : capabilities) {
                joiner.add(capabilityNameOf(c));
            }
        }
        return joiner.toString();
    }

    /**
     * @hide
     */
    public static @NonNull String capabilityNameOf(@NetCapability int capability) {
        switch (capability) {
            case NET_CAPABILITY_MMS:                  return "MMS";
            case NET_CAPABILITY_SUPL:                 return "SUPL";
            case NET_CAPABILITY_DUN:                  return "DUN";
            case NET_CAPABILITY_FOTA:                 return "FOTA";
            case NET_CAPABILITY_IMS:                  return "IMS";
            case NET_CAPABILITY_CBS:                  return "CBS";
            case NET_CAPABILITY_WIFI_P2P:             return "WIFI_P2P";
            case NET_CAPABILITY_IA:                   return "IA";
            case NET_CAPABILITY_RCS:                  return "RCS";
            case NET_CAPABILITY_XCAP:                 return "XCAP";
            case NET_CAPABILITY_EIMS:                 return "EIMS";
            case NET_CAPABILITY_NOT_METERED:          return "NOT_METERED";
            case NET_CAPABILITY_INTERNET:             return "INTERNET";
            case NET_CAPABILITY_NOT_RESTRICTED:       return "NOT_RESTRICTED";
            case NET_CAPABILITY_TRUSTED:              return "TRUSTED";
            case NET_CAPABILITY_NOT_VPN:              return "NOT_VPN";
            case NET_CAPABILITY_VALIDATED:            return "VALIDATED";
            case NET_CAPABILITY_CAPTIVE_PORTAL:       return "CAPTIVE_PORTAL";
            case NET_CAPABILITY_NOT_ROAMING:          return "NOT_ROAMING";
            case NET_CAPABILITY_FOREGROUND:           return "FOREGROUND";
            case NET_CAPABILITY_NOT_CONGESTED:        return "NOT_CONGESTED";
            case NET_CAPABILITY_NOT_SUSPENDED:        return "NOT_SUSPENDED";
            case NET_CAPABILITY_OEM_PAID:             return "OEM_PAID";
            case NET_CAPABILITY_MCX:                  return "MCX";
            case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY";
            default:                                  return Integer.toString(capability);
        }
    }

    /**
     * @hide
     */
    @UnsupportedAppUsage
    public static @NonNull String transportNamesOf(@Nullable @Transport int[] types) {
        StringJoiner joiner = new StringJoiner("|");
        if (types != null) {
            for (int t : types) {
                joiner.add(transportNameOf(t));
            }
        }
        return joiner.toString();
    }

    /**
     * @hide
     */
    public static @NonNull String transportNameOf(@Transport int transport) {
        if (!isValidTransport(transport)) {
            return "UNKNOWN";
        }
        return TRANSPORT_NAMES[transport];
    }

    private static void checkValidTransportType(@Transport int transport) {
        Preconditions.checkArgument(
                isValidTransport(transport), "Invalid TransportType " + transport);
    }

    private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) {
        return capability >= MIN_NET_CAPABILITY && capability <= MAX_NET_CAPABILITY;
    }

    private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) {
        Preconditions.checkArgument(isValidCapability(capability),
                "NetworkCapability " + capability + "out of range");
    }

    /**
     * Check if this {@code NetworkCapability} instance is metered.
     *
     * @return {@code true} if {@code NET_CAPABILITY_NOT_METERED} is not set on this instance.
     * @hide
     */
    public boolean isMetered() {
        return !hasCapability(NET_CAPABILITY_NOT_METERED);
    }
}