• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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.server.uwb.params;
18 
19 import static com.android.server.uwb.config.CapabilityParam.ADS_TWR;
20 import static com.android.server.uwb.config.CapabilityParam.ADVERTISER;
21 import static com.android.server.uwb.config.CapabilityParam.AOA_AZIMUTH_180;
22 import static com.android.server.uwb.config.CapabilityParam.AOA_AZIMUTH_90;
23 import static com.android.server.uwb.config.CapabilityParam.AOA_ELEVATION;
24 import static com.android.server.uwb.config.CapabilityParam.AOA_FOM;
25 import static com.android.server.uwb.config.CapabilityParam.AOA_RESULT_REQ_INTERLEAVING;
26 import static com.android.server.uwb.config.CapabilityParam.BLOCK_BASED_SCHEDULING;
27 import static com.android.server.uwb.config.CapabilityParam.BLOCK_STRIDING;
28 import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K3;
29 import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K7;
30 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_10;
31 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_12;
32 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_13;
33 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_14;
34 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_5;
35 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_6;
36 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_8;
37 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_9;
38 import static com.android.server.uwb.config.CapabilityParam.CONSTRAINT_LENGTH_3;
39 import static com.android.server.uwb.config.CapabilityParam.CONSTRAINT_LENGTH_7;
40 import static com.android.server.uwb.config.CapabilityParam.CONTENTION_BASED_RANGING;
41 import static com.android.server.uwb.config.CapabilityParam.DIAGNOSTICS;
42 import static com.android.server.uwb.config.CapabilityParam.DS_TWR_DEFERRED;
43 import static com.android.server.uwb.config.CapabilityParam.DS_TWR_NON_DEFERRED;
44 import static com.android.server.uwb.config.CapabilityParam.DT_ANCHOR;
45 import static com.android.server.uwb.config.CapabilityParam.DT_TAG;
46 import static com.android.server.uwb.config.CapabilityParam.DT_TAG_BLOCK_SKIPPING;
47 import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS;
48 import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY;
49 import static com.android.server.uwb.config.CapabilityParam.ESS_TWR_NON_DEFERRED;
50 import static com.android.server.uwb.config.CapabilityParam.EXTENDED_MAC_ADDRESS;
51 import static com.android.server.uwb.config.CapabilityParam.HOPPING_MODE;
52 import static com.android.server.uwb.config.CapabilityParam.INITIATOR;
53 import static com.android.server.uwb.config.CapabilityParam.INTERVAL_BASED_SCHEDULING;
54 import static com.android.server.uwb.config.CapabilityParam.MANY_TO_MANY;
55 import static com.android.server.uwb.config.CapabilityParam.OBSERVER;
56 import static com.android.server.uwb.config.CapabilityParam.ONE_TO_MANY;
57 import static com.android.server.uwb.config.CapabilityParam.OWR_AOA;
58 import static com.android.server.uwb.config.CapabilityParam.OWR_DL_TDOA;
59 import static com.android.server.uwb.config.CapabilityParam.OWR_UL_TDOA;
60 import static com.android.server.uwb.config.CapabilityParam.PROVISIONED_STS;
61 import static com.android.server.uwb.config.CapabilityParam.PROVISIONED_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY;
62 import static com.android.server.uwb.config.CapabilityParam.PSDU_LENGTH_SUPPORT;
63 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_DISABLE;
64 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE;
65 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG;
66 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG;
67 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG;
68 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG;
69 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG;
70 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG;
71 import static com.android.server.uwb.config.CapabilityParam.RESPONDER;
72 import static com.android.server.uwb.config.CapabilityParam.RSSI_REPORTING;
73 import static com.android.server.uwb.config.CapabilityParam.SP0;
74 import static com.android.server.uwb.config.CapabilityParam.SP1;
75 import static com.android.server.uwb.config.CapabilityParam.SP3;
76 import static com.android.server.uwb.config.CapabilityParam.SS_TWR_DEFERRED;
77 import static com.android.server.uwb.config.CapabilityParam.SS_TWR_NON_DEFERRED;
78 import static com.android.server.uwb.config.CapabilityParam.STATIC_STS;
79 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_RESULT_REQ_INTERLEAVING;
80 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_VER_1_0;
81 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_VER_2_0;
82 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BLOCK_STRIDING_VER_1_0;
83 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BLOCK_STRIDING_VER_2_0;
84 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BPRF_PARAMETER_SETS_VER_1_0;
85 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BPRF_PARAMETER_SETS_VER_2_0;
86 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CC_CONSTRAINT_LENGTH_VER_1_0;
87 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CC_CONSTRAINT_LENGTH_VER_2_0;
88 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CHANNELS_VER_1_0;
89 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CHANNELS_VER_2_0;
90 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_ROLES_VER_1_0;
91 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_ROLES_VER_2_0;
92 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_TYPE_VER_2_0;
93 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DIAGNOSTICS;
94 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DT_TAG_BLOCK_SKIPPING_2_0;
95 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DT_TAG_MAX_ACTIVE_RR_2_0;
96 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_EXTENDED_MAC_ADDRESS_VER_1_0;
97 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_EXTENDED_MAC_ADDRESS_VER_2_0;
98 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_1_0;
99 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_2_0;
100 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_1_0;
101 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_2_0;
102 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HOPPING_MODE_VER_1_0;
103 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HOPPING_MODE_VER_2_0;
104 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HPRF_PARAMETER_SETS_VER_1_0;
105 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HPRF_PARAMETER_SETS_VER_2_0;
106 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_1_0;
107 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_2_0;
108 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_MESSAGE_SIZE_VER_1_0;
109 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_MESSAGE_SIZE_VER_2_0;
110 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_RANGING_SESSION_NUMBER;
111 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MIN_RANGING_INTERVAL_MS;
112 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MIN_SLOT_DURATION_RSTU;
113 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MULTI_NODE_MODES_VER_1_0;
114 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MULTI_NODE_MODES_VER_2_0;
115 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_PSDU_LENGTH_2_0;
116 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGE_DATA_NTF_CONFIG;
117 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_METHOD_VER_1_0;
118 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_METHOD_VER_2_0;
119 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_TIME_STRUCT_VER_1_0;
120 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_TIME_STRUCT_VER_2_0;
121 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RFRAME_CONFIG_VER_1_0;
122 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RFRAME_CONFIG_VER_2_0;
123 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RSSI_REPORTING;
124 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SCHEDULED_MODE_VER_1_0;
125 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SCHEDULED_MODE_VER_2_0;
126 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SESSION_KEY_LENGTH_VER_2_0;
127 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_STS_CONFIG_VER_1_0;
128 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_STS_CONFIG_VER_2_0;
129 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SUSPEND_RANGING_VER_2_0;
130 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_UWB_INITIATION_TIME_VER_1_0;
131 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_UWB_INITIATION_TIME_VER_2_0;
132 import static com.android.server.uwb.config.CapabilityParam.TIME_SCHEDULED_RANGING;
133 import static com.android.server.uwb.config.CapabilityParam.UNICAST;
134 import static com.android.server.uwb.config.CapabilityParam.UT_ANCHOR;
135 import static com.android.server.uwb.config.CapabilityParam.UT_SYNCHRONIZATION_ANCHOR;
136 import static com.android.server.uwb.config.CapabilityParam.UT_TAG;
137 import static com.android.server.uwb.config.CapabilityParam.UWB_INITIATION_TIME;
138 
139 import android.util.Log;
140 
141 import com.android.server.uwb.UwbInjector;
142 
143 import com.google.uwb.support.base.FlagEnum;
144 import com.google.uwb.support.base.Params;
145 import com.google.uwb.support.base.ProtocolVersion;
146 import com.google.uwb.support.fira.FiraParams;
147 import com.google.uwb.support.fira.FiraParams.BprfParameterSetCapabilityFlag;
148 import com.google.uwb.support.fira.FiraParams.CcConstraintLengthCapabilitiesFlag;
149 import com.google.uwb.support.fira.FiraParams.DeviceRoleCapabilityFlag;
150 import com.google.uwb.support.fira.FiraParams.HprfParameterSetCapabilityFlag;
151 import com.google.uwb.support.fira.FiraParams.MultiNodeCapabilityFlag;
152 import com.google.uwb.support.fira.FiraParams.PsduDataRateCapabilityFlag;
153 import com.google.uwb.support.fira.FiraParams.RangingRoundCapabilityFlag;
154 import com.google.uwb.support.fira.FiraParams.RangingTimeStructCapabilitiesFlag;
155 import com.google.uwb.support.fira.FiraParams.RframeCapabilityFlag;
156 import com.google.uwb.support.fira.FiraParams.SchedulingModeCapabilitiesFlag;
157 import com.google.uwb.support.fira.FiraParams.StsCapabilityFlag;
158 import com.google.uwb.support.fira.FiraProtocolVersion;
159 import com.google.uwb.support.fira.FiraSpecificationParams;
160 
161 import java.math.BigInteger;
162 import java.util.ArrayList;
163 import java.util.EnumSet;
164 import java.util.List;
165 import java.util.stream.IntStream;
166 
167 public class FiraDecoder extends TlvDecoder {
168     private static final String TAG = "FiraDecoder";
169 
170     private final UwbInjector mUwbInjector;
171 
FiraDecoder(UwbInjector uwbInjector)172     public FiraDecoder(UwbInjector uwbInjector) {
173         mUwbInjector = uwbInjector;
174     }
175 
176     @Override
getParams(TlvDecoderBuffer tlvs, Class<T> paramType, ProtocolVersion protocolVersion)177     public <T extends Params> T getParams(TlvDecoderBuffer tlvs, Class<T> paramType,
178             ProtocolVersion protocolVersion) {
179         if (FiraSpecificationParams.class.equals(paramType)) {
180             // The "protocolVersion" is always expected to be of type "FiraProtocolVersion" here,
181             // but in case it's not, we use a backup value of "PROTOCOL_VERSION_1_1".
182             FiraProtocolVersion uwbsFiraProtocolVersion =
183                     (protocolVersion instanceof FiraProtocolVersion)
184                         ? (FiraProtocolVersion) protocolVersion : FiraParams.PROTOCOL_VERSION_1_1;
185             return (T) getFiraSpecificationParamsFromTlvBuffer(tlvs, uwbsFiraProtocolVersion);
186         }
187         return null;
188     }
189 
isBitSet(int flags, int mask)190     private static boolean isBitSet(int flags, int mask) {
191         return (flags & mask) != 0;
192     }
193 
getFiraSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs, ProtocolVersion protocolVersion)194     private FiraSpecificationParams getFiraSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs,
195                     ProtocolVersion protocolVersion) {
196         FiraSpecificationParams.Builder builder = new FiraSpecificationParams.Builder();
197         byte[] versionCheck = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_2_0);
198         if (versionCheck.length == 1) {
199             // FiRa Version 1.0
200             byte[] phyVersions = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_1_0);
201             builder.setMinPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 0));
202             builder.setMaxPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 2));
203             byte[] macVersions = tlvs.getByteArray(SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_1_0);
204             builder.setMinMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 0));
205             builder.setMaxMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 2));
206 
207             byte deviceRolesUci = tlvs.getByte(SUPPORTED_DEVICE_ROLES_VER_1_0);
208             EnumSet<DeviceRoleCapabilityFlag> deviceRoles =
209                     EnumSet.noneOf(DeviceRoleCapabilityFlag.class);
210             if (isBitSet(deviceRolesUci, INITIATOR)) {
211                 // This assumes both controller + controlee is supported.
212                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_INITIATOR_SUPPORT);
213                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_INITIATOR_SUPPORT);
214             }
215             if (isBitSet(deviceRolesUci, RESPONDER)) {
216                 // This assumes both controller + controlee is supported.
217                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_RESPONDER_SUPPORT);
218                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_RESPONDER_SUPPORT);
219             }
220             builder.setDeviceRoleCapabilities(deviceRoles);
221 
222             byte rangingMethodUci = tlvs.getByte(SUPPORTED_RANGING_METHOD_VER_1_0);
223             EnumSet<RangingRoundCapabilityFlag> rangingRoundFlag = EnumSet.noneOf(
224                     RangingRoundCapabilityFlag.class);
225             if (isBitSet(rangingMethodUci, DS_TWR_DEFERRED)) {
226                 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_DS_TWR_SUPPORT);
227             }
228             if (isBitSet(rangingMethodUci, SS_TWR_DEFERRED)) {
229                 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_SS_TWR_SUPPORT);
230             }
231             builder.setRangingRoundCapabilities(rangingRoundFlag);
232 
233             // TODO(b/209053358): This does not align with UCI spec.
234             if (isBitSet(rangingMethodUci, DS_TWR_NON_DEFERRED)
235                     || isBitSet(rangingMethodUci, SS_TWR_NON_DEFERRED)) {
236                 builder.hasNonDeferredModeSupport(true);
237             }
238 
239             byte stsConfigUci = tlvs.getByte(SUPPORTED_STS_CONFIG_VER_1_0);
240             EnumSet<StsCapabilityFlag> stsCapabilityFlag = EnumSet.noneOf(StsCapabilityFlag.class);
241             if (isBitSet(stsConfigUci, STATIC_STS)) {
242                 stsCapabilityFlag.add(StsCapabilityFlag.HAS_STATIC_STS_SUPPORT);
243             }
244             if (isBitSet(stsConfigUci, DYNAMIC_STS)) {
245                 stsCapabilityFlag.add(StsCapabilityFlag.HAS_DYNAMIC_STS_SUPPORT);
246             }
247             if (isBitSet(stsConfigUci, DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) {
248                 stsCapabilityFlag.add(
249                         StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT);
250             }
251             if (isBitSet(stsConfigUci, PROVISIONED_STS)) {
252                 stsCapabilityFlag.add(StsCapabilityFlag.HAS_PROVISIONED_STS_SUPPORT);
253             }
254             if (isBitSet(stsConfigUci, PROVISIONED_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) {
255                 stsCapabilityFlag.add(
256                         StsCapabilityFlag.HAS_PROVISIONED_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT);
257             }
258             builder.setStsCapabilities(stsCapabilityFlag);
259 
260             byte multiNodeUci = tlvs.getByte(SUPPORTED_MULTI_NODE_MODES_VER_1_0);
261             EnumSet<MultiNodeCapabilityFlag> multiNodeFlag =
262                     EnumSet.noneOf(MultiNodeCapabilityFlag.class);
263             if (isBitSet(multiNodeUci, UNICAST)) {
264                 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_UNICAST_SUPPORT);
265             }
266             if (isBitSet(multiNodeUci, ONE_TO_MANY)) {
267                 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_ONE_TO_MANY_SUPPORT);
268             }
269             if (isBitSet(multiNodeUci, MANY_TO_MANY)) {
270                 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_MANY_TO_MANY_SUPPORT);
271             }
272             builder.setMultiNodeCapabilities(multiNodeFlag);
273 
274             byte rangingTimeStructUci = tlvs.getByte(SUPPORTED_RANGING_TIME_STRUCT_VER_1_0);
275             EnumSet<RangingTimeStructCapabilitiesFlag> rangingTimeStructFlag =
276                     EnumSet.noneOf(RangingTimeStructCapabilitiesFlag.class);
277             if (protocolVersion.getMajor() <= 2
278                     && isBitSet(rangingTimeStructUci, INTERVAL_BASED_SCHEDULING)) {
279                 rangingTimeStructFlag.add(
280                         RangingTimeStructCapabilitiesFlag.HAS_INTERVAL_BASED_SCHEDULING_SUPPORT);
281             }
282             if (isBitSet(rangingTimeStructUci, BLOCK_BASED_SCHEDULING)) {
283                 rangingTimeStructFlag.add(
284                         RangingTimeStructCapabilitiesFlag.HAS_BLOCK_BASED_SCHEDULING_SUPPORT);
285             }
286             builder.setRangingTimeStructCapabilities(rangingTimeStructFlag);
287 
288             byte schedulingModeUci = tlvs.getByte(SUPPORTED_SCHEDULED_MODE_VER_1_0);
289             EnumSet<SchedulingModeCapabilitiesFlag> schedulingModeFlag =
290                     EnumSet.noneOf(SchedulingModeCapabilitiesFlag.class);
291             if (isBitSet(schedulingModeUci, CONTENTION_BASED_RANGING)) {
292                 schedulingModeFlag.add(
293                         SchedulingModeCapabilitiesFlag.HAS_CONTENTION_BASED_RANGING_SUPPORT);
294             }
295             if (isBitSet(schedulingModeUci, TIME_SCHEDULED_RANGING)) {
296                 schedulingModeFlag.add(
297                         SchedulingModeCapabilitiesFlag.HAS_TIME_SCHEDULED_RANGING_SUPPORT);
298             }
299             builder.setSchedulingModeCapabilities(schedulingModeFlag);
300 
301             byte ccConstraintLengthUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_1_0);
302             EnumSet<CcConstraintLengthCapabilitiesFlag> ccConstraintLengthFlag =
303                     EnumSet.noneOf(CcConstraintLengthCapabilitiesFlag.class);
304             if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_3)) {
305                 ccConstraintLengthFlag.add(
306                         CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_3_SUPPORT);
307             }
308             if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_7)) {
309                 ccConstraintLengthFlag.add(
310                         CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_7_SUPPORT);
311             }
312             builder.setCcConstraintLengthCapabilities(ccConstraintLengthFlag);
313 
314             byte blockStridingUci = tlvs.getByte(SUPPORTED_BLOCK_STRIDING_VER_1_0);
315             if (isBitSet(blockStridingUci, BLOCK_STRIDING)) {
316                 builder.hasBlockStridingSupport(true);
317             }
318 
319             byte hoppingPreferenceUci = tlvs.getByte(SUPPORTED_HOPPING_MODE_VER_1_0);
320             if (isBitSet(hoppingPreferenceUci, HOPPING_MODE)) {
321                 builder.hasHoppingPreferenceSupport(true);
322             }
323 
324             byte extendedMacAddressUci = tlvs.getByte(SUPPORTED_EXTENDED_MAC_ADDRESS_VER_1_0);
325             if (isBitSet(extendedMacAddressUci, EXTENDED_MAC_ADDRESS)) {
326                 builder.hasExtendedMacAddressSupport(true);
327             }
328 
329             byte initiationTimeUci = tlvs.getByte(SUPPORTED_UWB_INITIATION_TIME_VER_1_0);
330             if (isBitSet(initiationTimeUci, UWB_INITIATION_TIME)) {
331                 builder.hasInitiationTimeSupport(true);
332             }
333 
334             byte channelsUci = tlvs.getByte(SUPPORTED_CHANNELS_VER_1_0);
335             List<Integer> channels = new ArrayList<>();
336             if (isBitSet(channelsUci, CHANNEL_5)) {
337                 channels.add(5);
338             }
339             if (isBitSet(channelsUci, CHANNEL_6)) {
340                 channels.add(6);
341             }
342             if (isBitSet(channelsUci, CHANNEL_8)) {
343                 channels.add(8);
344             }
345             if (isBitSet(channelsUci, CHANNEL_9)) {
346                 channels.add(9);
347             }
348             if (isBitSet(channelsUci, CHANNEL_10)) {
349                 channels.add(10);
350             }
351             if (isBitSet(channelsUci, CHANNEL_12)) {
352                 channels.add(12);
353             }
354             if (isBitSet(channelsUci, CHANNEL_13)) {
355                 channels.add(13);
356             }
357             if (isBitSet(channelsUci, CHANNEL_14)) {
358                 channels.add(14);
359             }
360             builder.setSupportedChannels(channels);
361 
362             byte rframeConfigUci = tlvs.getByte(SUPPORTED_RFRAME_CONFIG_VER_1_0);
363             EnumSet<RframeCapabilityFlag> rframeConfigFlag =
364                     EnumSet.noneOf(RframeCapabilityFlag.class);
365             if (isBitSet(rframeConfigUci, SP0)) {
366                 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT);
367             }
368             if (isBitSet(rframeConfigUci, SP1)) {
369                 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT);
370             }
371             if (isBitSet(rframeConfigUci, SP3)) {
372                 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT);
373             }
374             builder.setRframeCapabilities(rframeConfigFlag);
375 
376             byte bprfSets = tlvs.getByte(SUPPORTED_BPRF_PARAMETER_SETS_VER_1_0);
377             int bprfSetsValue = Integer.valueOf(bprfSets);
378             EnumSet<BprfParameterSetCapabilityFlag> bprfFlag;
379             bprfFlag = FlagEnum.toEnumSet(bprfSetsValue, BprfParameterSetCapabilityFlag.values());
380             builder.setBprfParameterSetCapabilities(bprfFlag);
381 
382             byte[] hprfSets = tlvs.getByteArray(SUPPORTED_HPRF_PARAMETER_SETS_VER_1_0);
383             // Extend the 5 bytes from HAL to 8 bytes for long.
384             long hprfSetsValue = new BigInteger(TlvUtil.getReverseBytes(hprfSets)).longValue();
385             EnumSet<HprfParameterSetCapabilityFlag> hprfFlag;
386             hprfFlag = FlagEnum.longToEnumSet(
387                     hprfSetsValue, HprfParameterSetCapabilityFlag.values());
388             builder.setHprfParameterSetCapabilities(hprfFlag);
389 
390             EnumSet<FiraParams.PrfCapabilityFlag> prfFlag =
391                     EnumSet.noneOf(FiraParams.PrfCapabilityFlag.class);
392             boolean hasBprfSupport = bprfSets != 0;
393             if (hasBprfSupport) {
394                 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_BPRF_SUPPORT);
395             }
396             boolean hasHprfSupport =
397                     IntStream.range(0, hprfSets.length).parallel().anyMatch(i -> hprfSets[i] != 0);
398             if (hasHprfSupport) {
399                 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_HPRF_SUPPORT);
400             }
401             builder.setPrfCapabilities(prfFlag);
402 
403             byte ccConstraintUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_1_0);
404             EnumSet<PsduDataRateCapabilityFlag> psduRateFlag =
405                     EnumSet.noneOf(PsduDataRateCapabilityFlag.class);
406             if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasBprfSupport) {
407                 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_6M81_SUPPORT);
408             }
409             if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasBprfSupport) {
410                 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_7M80_SUPPORT);
411             }
412             if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasHprfSupport) {
413                 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_27M2_SUPPORT);
414             }
415             if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasHprfSupport) {
416                 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_31M2_SUPPORT);
417             }
418             builder.setPsduDataRateCapabilities(psduRateFlag);
419 
420             byte aoaUci = tlvs.getByte(SUPPORTED_AOA_VER_1_0);
421             EnumSet<FiraParams.AoaCapabilityFlag> aoaFlag =
422                     EnumSet.noneOf(FiraParams.AoaCapabilityFlag.class);
423             if (isBitSet(aoaUci, AOA_AZIMUTH_90)) {
424                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_AZIMUTH_SUPPORT);
425             }
426             if (isBitSet(aoaUci, AOA_AZIMUTH_180)) {
427                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FULL_AZIMUTH_SUPPORT);
428             }
429             if (isBitSet(aoaUci, AOA_ELEVATION)) {
430                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_ELEVATION_SUPPORT);
431             }
432             if (isBitSet(aoaUci, AOA_FOM)) {
433                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FOM_SUPPORT);
434             }
435             byte aoaInterleavingUci = tlvs.getByte(SUPPORTED_AOA_RESULT_REQ_INTERLEAVING);
436             if (isBitSet(aoaInterleavingUci, AOA_RESULT_REQ_INTERLEAVING)) {
437                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_INTERLEAVING_SUPPORT);
438             }
439             builder.setAoaCapabilities(aoaFlag);
440 
441             try {
442                 int maxMessageSizeUci = tlvs.getShort(SUPPORTED_MAX_MESSAGE_SIZE_VER_1_0);
443                 builder.setMaxMessageSize(Integer.valueOf(maxMessageSizeUci));
444             } catch (IllegalArgumentException e) {
445                 Log.w(TAG, "SUPPORTED_MAX_MESSAGE_SIZE not found.");
446             }
447             try {
448                 int maxDataPacketPayloadSizeUci = tlvs.getShort(
449                         SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_1_0);
450                 builder.setMaxDataPacketPayloadSize(Integer.valueOf(maxDataPacketPayloadSizeUci));
451             } catch (IllegalArgumentException e) {
452                 Log.w(TAG, "SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE not found.");
453             }
454         } else if (versionCheck.length == 4) {
455             // FiRa Version 2.0
456             byte[] phyVersions = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_2_0);
457             builder.setMinPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 0));
458             builder.setMaxPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 2));
459             byte[] macVersions = tlvs.getByteArray(SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_2_0);
460             builder.setMinMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 0));
461             builder.setMaxMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 2));
462 
463             byte[] deviceRolesUci = tlvs.getByteArray(SUPPORTED_DEVICE_ROLES_VER_2_0);
464             EnumSet<DeviceRoleCapabilityFlag> deviceRoles =
465                     EnumSet.noneOf(DeviceRoleCapabilityFlag.class);
466             if (isBitSet(deviceRolesUci[0], INITIATOR)) {
467                 // This assumes both controller + controlee is supported.
468                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_INITIATOR_SUPPORT);
469                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_INITIATOR_SUPPORT);
470             }
471             if (isBitSet(deviceRolesUci[0], RESPONDER)) {
472                 // This assumes both controller + controlee is supported.
473                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_RESPONDER_SUPPORT);
474                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_RESPONDER_SUPPORT);
475             }
476             if (isBitSet(deviceRolesUci[0], UT_SYNCHRONIZATION_ANCHOR)) {
477                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_UT_SYNCHRONIZATION_SUPPORT);
478             }
479             if (isBitSet(deviceRolesUci[0], UT_ANCHOR)) {
480                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_UT_ANCHOR_SUPPORT);
481             }
482             if (isBitSet(deviceRolesUci[0], UT_TAG)) {
483                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_UT_TAG_SUPPORT);
484             }
485             if (isBitSet(deviceRolesUci[0], ADVERTISER)) {
486                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_ADVERTISER_SUPPORT);
487             }
488             if (isBitSet(deviceRolesUci[0], OBSERVER)) {
489                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_OBSERVER_SUPPORT);
490             }
491             if (isBitSet(deviceRolesUci[0], DT_ANCHOR)) {
492                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_DT_ANCHOR_SUPPORT);
493             }
494             if (isBitSet(deviceRolesUci[1], DT_TAG)) {
495                 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_DT_TAG_SUPPORT);
496             }
497             builder.setDeviceRoleCapabilities(deviceRoles);
498 
499             byte[] rangingMethodUci = tlvs.getByteArray(SUPPORTED_RANGING_METHOD_VER_2_0);
500             EnumSet<RangingRoundCapabilityFlag> rangingRoundFlag = EnumSet.noneOf(
501                     RangingRoundCapabilityFlag.class);
502             if (isBitSet(rangingMethodUci[0], DS_TWR_DEFERRED)) {
503                 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_DS_TWR_SUPPORT);
504             }
505             if (isBitSet(rangingMethodUci[0], SS_TWR_DEFERRED)) {
506                 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_SS_TWR_SUPPORT);
507             }
508             if (isBitSet(rangingMethodUci[0], OWR_UL_TDOA)) {
509                 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_OWR_UL_TDOA_SUPPORT);
510             }
511             if (isBitSet(rangingMethodUci[0], OWR_DL_TDOA)) {
512                 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_OWR_DL_TDOA_SUPPORT);
513             }
514             if (isBitSet(rangingMethodUci[0], OWR_AOA)) {
515                 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_OWR_AOA_SUPPORT);
516             }
517             if (isBitSet(rangingMethodUci[0], ESS_TWR_NON_DEFERRED)) {
518                 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_ESS_TWR_SUPPORT);
519             }
520             if (isBitSet(rangingMethodUci[1], ADS_TWR)) {
521                 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_ADS_TWR_SUPPORT);
522             }
523             builder.setRangingRoundCapabilities(rangingRoundFlag);
524 
525             // TODO(b/209053358): This does not align with UCI spec.
526             if (isBitSet(rangingMethodUci[0], DS_TWR_NON_DEFERRED)
527                     || isBitSet(rangingMethodUci[0], SS_TWR_NON_DEFERRED)) {
528                 builder.hasNonDeferredModeSupport(true);
529             }
530 
531             byte stsConfigUci = tlvs.getByte(SUPPORTED_STS_CONFIG_VER_2_0);
532             EnumSet<StsCapabilityFlag> stsCapabilityFlag = EnumSet.noneOf(StsCapabilityFlag.class);
533             if (isBitSet(stsConfigUci, STATIC_STS)) {
534                 stsCapabilityFlag.add(StsCapabilityFlag.HAS_STATIC_STS_SUPPORT);
535             }
536             if (isBitSet(stsConfigUci, DYNAMIC_STS)) {
537                 stsCapabilityFlag.add(StsCapabilityFlag.HAS_DYNAMIC_STS_SUPPORT);
538             }
539             if (isBitSet(stsConfigUci, DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) {
540                 stsCapabilityFlag.add(
541                         StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT);
542             }
543             if (isBitSet(stsConfigUci, PROVISIONED_STS)) {
544                 stsCapabilityFlag.add(StsCapabilityFlag.HAS_PROVISIONED_STS_SUPPORT);
545             }
546             if (isBitSet(stsConfigUci, PROVISIONED_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) {
547                 stsCapabilityFlag.add(
548                         StsCapabilityFlag.HAS_PROVISIONED_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT);
549             }
550             builder.setStsCapabilities(stsCapabilityFlag);
551 
552             byte multiNodeUci = tlvs.getByte(SUPPORTED_MULTI_NODE_MODES_VER_2_0);
553             EnumSet<MultiNodeCapabilityFlag> multiNodeFlag =
554                     EnumSet.noneOf(MultiNodeCapabilityFlag.class);
555             if (isBitSet(multiNodeUci, UNICAST)) {
556                 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_UNICAST_SUPPORT);
557             }
558             if (isBitSet(multiNodeUci, ONE_TO_MANY)) {
559                 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_ONE_TO_MANY_SUPPORT);
560             }
561             if (isBitSet(multiNodeUci, MANY_TO_MANY)) {
562                 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_MANY_TO_MANY_SUPPORT);
563             }
564             builder.setMultiNodeCapabilities(multiNodeFlag);
565 
566             byte rangingTimeStructUci = tlvs.getByte(SUPPORTED_RANGING_TIME_STRUCT_VER_2_0);
567             EnumSet<RangingTimeStructCapabilitiesFlag> rangingTimeStructFlag =
568                     EnumSet.noneOf(RangingTimeStructCapabilitiesFlag.class);
569             if (isBitSet(rangingTimeStructUci, BLOCK_BASED_SCHEDULING)) {
570                 rangingTimeStructFlag.add(
571                         RangingTimeStructCapabilitiesFlag.HAS_BLOCK_BASED_SCHEDULING_SUPPORT);
572             }
573             builder.setRangingTimeStructCapabilities(rangingTimeStructFlag);
574 
575             byte schedulingModeUci = tlvs.getByte(SUPPORTED_SCHEDULED_MODE_VER_2_0);
576             EnumSet<SchedulingModeCapabilitiesFlag> schedulingModeFlag =
577                     EnumSet.noneOf(SchedulingModeCapabilitiesFlag.class);
578             if (isBitSet(schedulingModeUci, CONTENTION_BASED_RANGING)) {
579                 schedulingModeFlag.add(
580                         SchedulingModeCapabilitiesFlag.HAS_CONTENTION_BASED_RANGING_SUPPORT);
581             }
582             if (isBitSet(schedulingModeUci, TIME_SCHEDULED_RANGING)) {
583                 schedulingModeFlag.add(
584                         SchedulingModeCapabilitiesFlag.HAS_TIME_SCHEDULED_RANGING_SUPPORT);
585             }
586             builder.setSchedulingModeCapabilities(schedulingModeFlag);
587 
588             byte ccConstraintLengthUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_2_0);
589             EnumSet<CcConstraintLengthCapabilitiesFlag> ccConstraintLengthFlag =
590                     EnumSet.noneOf(CcConstraintLengthCapabilitiesFlag.class);
591             if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_3)) {
592                 ccConstraintLengthFlag.add(
593                         CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_3_SUPPORT);
594             }
595             if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_7)) {
596                 ccConstraintLengthFlag.add(
597                         CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_7_SUPPORT);
598             }
599             builder.setCcConstraintLengthCapabilities(ccConstraintLengthFlag);
600 
601             byte blockStridingUci = tlvs.getByte(SUPPORTED_BLOCK_STRIDING_VER_2_0);
602             if (isBitSet(blockStridingUci, BLOCK_STRIDING)) {
603                 builder.hasBlockStridingSupport(true);
604             }
605 
606             byte hoppingPreferenceUci = tlvs.getByte(SUPPORTED_HOPPING_MODE_VER_2_0);
607             if (isBitSet(hoppingPreferenceUci, HOPPING_MODE)) {
608                 builder.hasHoppingPreferenceSupport(true);
609             }
610 
611             byte extendedMacAddressUci = tlvs.getByte(SUPPORTED_EXTENDED_MAC_ADDRESS_VER_2_0);
612             if (isBitSet(extendedMacAddressUci, EXTENDED_MAC_ADDRESS)) {
613                 builder.hasExtendedMacAddressSupport(true);
614             }
615 
616             byte initiationTimeUci = tlvs.getByte(SUPPORTED_UWB_INITIATION_TIME_VER_2_0);
617             if (isBitSet(initiationTimeUci, UWB_INITIATION_TIME)) {
618                 builder.hasInitiationTimeSupport(true);
619             }
620 
621             byte channelsUci = tlvs.getByte(SUPPORTED_CHANNELS_VER_2_0);
622             List<Integer> channels = new ArrayList<>();
623             if (isBitSet(channelsUci, CHANNEL_5)) {
624                 channels.add(5);
625             }
626             if (isBitSet(channelsUci, CHANNEL_6)) {
627                 channels.add(6);
628             }
629             if (isBitSet(channelsUci, CHANNEL_8)) {
630                 channels.add(8);
631             }
632             if (isBitSet(channelsUci, CHANNEL_9)) {
633                 channels.add(9);
634             }
635             if (isBitSet(channelsUci, CHANNEL_10)) {
636                 channels.add(10);
637             }
638             if (isBitSet(channelsUci, CHANNEL_12)) {
639                 channels.add(12);
640             }
641             if (isBitSet(channelsUci, CHANNEL_13)) {
642                 channels.add(13);
643             }
644             if (isBitSet(channelsUci, CHANNEL_14)) {
645                 channels.add(14);
646             }
647             builder.setSupportedChannels(channels);
648 
649             byte rframeConfigUci = tlvs.getByte(SUPPORTED_RFRAME_CONFIG_VER_2_0);
650             EnumSet<RframeCapabilityFlag> rframeConfigFlag =
651                     EnumSet.noneOf(RframeCapabilityFlag.class);
652             if (isBitSet(rframeConfigUci, SP0)) {
653                 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT);
654             }
655             if (isBitSet(rframeConfigUci, SP1)) {
656                 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT);
657             }
658             if (isBitSet(rframeConfigUci, SP3)) {
659                 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT);
660             }
661             builder.setRframeCapabilities(rframeConfigFlag);
662 
663             byte bprfSets = tlvs.getByte(SUPPORTED_BPRF_PARAMETER_SETS_VER_2_0);
664             int bprfSetsValue = Integer.valueOf(bprfSets);
665             EnumSet<BprfParameterSetCapabilityFlag> bprfFlag;
666             bprfFlag = FlagEnum.toEnumSet(bprfSetsValue, BprfParameterSetCapabilityFlag.values());
667             builder.setBprfParameterSetCapabilities(bprfFlag);
668 
669             byte[] hprfSets = tlvs.getByteArray(SUPPORTED_HPRF_PARAMETER_SETS_VER_2_0);
670             // Extend the 5 bytes from HAL to 8 bytes for long.
671             long hprfSetsValue = new BigInteger(TlvUtil.getReverseBytes(hprfSets)).longValue();
672             EnumSet<HprfParameterSetCapabilityFlag> hprfFlag;
673             hprfFlag = FlagEnum.longToEnumSet(
674                     hprfSetsValue, HprfParameterSetCapabilityFlag.values());
675             builder.setHprfParameterSetCapabilities(hprfFlag);
676 
677             EnumSet<FiraParams.PrfCapabilityFlag> prfFlag =
678                     EnumSet.noneOf(FiraParams.PrfCapabilityFlag.class);
679             boolean hasBprfSupport = bprfSets != 0;
680             if (hasBprfSupport) {
681                 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_BPRF_SUPPORT);
682             }
683             boolean hasHprfSupport =
684                     IntStream.range(0, hprfSets.length).parallel().anyMatch(i -> hprfSets[i] != 0);
685             if (hasHprfSupport) {
686                 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_HPRF_SUPPORT);
687             }
688             builder.setPrfCapabilities(prfFlag);
689 
690             byte ccConstraintUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_2_0);
691             EnumSet<PsduDataRateCapabilityFlag> psduRateFlag =
692                     EnumSet.noneOf(PsduDataRateCapabilityFlag.class);
693             if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasBprfSupport) {
694                 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_6M81_SUPPORT);
695             }
696             if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasBprfSupport) {
697                 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_7M80_SUPPORT);
698             }
699             if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasHprfSupport) {
700                 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_27M2_SUPPORT);
701             }
702             if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasHprfSupport) {
703                 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_31M2_SUPPORT);
704             }
705             builder.setPsduDataRateCapabilities(psduRateFlag);
706 
707             byte aoaUci = tlvs.getByte(SUPPORTED_AOA_VER_2_0);
708             EnumSet<FiraParams.AoaCapabilityFlag> aoaFlag =
709                     EnumSet.noneOf(FiraParams.AoaCapabilityFlag.class);
710             if (isBitSet(aoaUci, AOA_AZIMUTH_90)) {
711                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_AZIMUTH_SUPPORT);
712             }
713             if (isBitSet(aoaUci, AOA_AZIMUTH_180)) {
714                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FULL_AZIMUTH_SUPPORT);
715             }
716             if (isBitSet(aoaUci, AOA_ELEVATION)) {
717                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_ELEVATION_SUPPORT);
718             }
719             if (isBitSet(aoaUci, AOA_FOM)) {
720                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FOM_SUPPORT);
721             }
722             byte aoaInterleavingUci = tlvs.getByte(SUPPORTED_AOA_RESULT_REQ_INTERLEAVING);
723             if (isBitSet(aoaInterleavingUci, AOA_RESULT_REQ_INTERLEAVING)) {
724                 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_INTERLEAVING_SUPPORT);
725             }
726             builder.setAoaCapabilities(aoaFlag);
727 
728             try {
729                 int maxMessageSizeUci = tlvs.getShort(SUPPORTED_MAX_MESSAGE_SIZE_VER_2_0);
730                 builder.setMaxMessageSize(Integer.valueOf(maxMessageSizeUci));
731             } catch (IllegalArgumentException e) {
732                 Log.w(TAG, "SUPPORTED_MAX_MESSAGE_SIZE not found.");
733             }
734             try {
735                 int maxDataPacketPayloadSizeUci = tlvs.getShort(
736                         SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_2_0);
737                 builder.setMaxDataPacketPayloadSize(Integer.valueOf(maxDataPacketPayloadSizeUci));
738             } catch (IllegalArgumentException e) {
739                 Log.w(TAG, "SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE not found.");
740             }
741 
742             int deviceType = tlvs.getByte(SUPPORTED_DEVICE_TYPE_VER_2_0);
743             builder.setDeviceType(deviceType);
744 
745             int supportedSuspendSupport = tlvs.getByte(SUPPORTED_SUSPEND_RANGING_VER_2_0);
746             builder.setSuspendRangingSupport(supportedSuspendSupport != 0);
747 
748             int sessionKeyLength = tlvs.getByte(SUPPORTED_SESSION_KEY_LENGTH_VER_2_0);
749             builder.setSessionKeyLength(sessionKeyLength);
750 
751             try {
752                 int dtTagMaxActiveRr = tlvs.getByte(SUPPORTED_DT_TAG_MAX_ACTIVE_RR_2_0);
753                 builder.setDtTagMaxActiveRr(dtTagMaxActiveRr);
754             } catch (IllegalArgumentException e) {
755                 Log.w(TAG, "SUPPORTED_DT_TAG_MAX_ACTIVE_RR not found.");
756             }
757 
758             try {
759                 byte dtTagBlockSkippingUci = tlvs.getByte(SUPPORTED_DT_TAG_BLOCK_SKIPPING_2_0);
760                 if (isBitSet(dtTagBlockSkippingUci, DT_TAG_BLOCK_SKIPPING)) {
761                     builder.setDtTagBlockSkippingSupport(true);
762                 }
763             } catch (IllegalArgumentException e) {
764                 Log.w(TAG, "SUPPORTED_DT_TAG_BLOCK_SKIPPING_2_0 not found.");
765             }
766 
767             try {
768                 byte psduLengthUci = tlvs.getByte(SUPPORTED_PSDU_LENGTH_2_0);
769                 if (isBitSet(psduLengthUci, PSDU_LENGTH_SUPPORT)) {
770                     builder.setPsduLengthSupport(true);
771                 }
772             } catch (IllegalArgumentException e) {
773                 Log.w(TAG, "SUPPORTED_PSDU_LENGTH_2_0 not found.");
774             }
775         } else {
776             // This FiRa version is not supported yet.
777             return null;
778         }
779         try {
780             int minRangingInterval = tlvs.getInt(SUPPORTED_MIN_RANGING_INTERVAL_MS);
781             builder.setMinRangingIntervalSupported(minRangingInterval);
782         } catch (IllegalArgumentException e) {
783             Log.w(TAG, "SUPPORTED_MIN_RANGING_INTERVAL_MS not found.");
784         }
785 
786         try {
787             int minSlotDurationUs = TlvUtil.rstuToUs(tlvs.getInt(SUPPORTED_MIN_SLOT_DURATION_RSTU));
788             builder.setMinSlotDurationSupportedUs(minSlotDurationUs);
789         } catch (IllegalArgumentException e) {
790             Log.w(TAG, "SUPPORTED_MIN_SLOT_DURATION not found.");
791         }
792 
793         try {
794             int maxRangingSessionNumber = tlvs.getInt(SUPPORTED_MAX_RANGING_SESSION_NUMBER);
795             builder.setMaxRangingSessionNumberSupported(maxRangingSessionNumber);
796         } catch (IllegalArgumentException e) {
797             Log.w(TAG, "SUPPORTED_MAX_RANGING_SESSION_NUMBER not found");
798         }
799 
800         try {
801             byte rssiReporting = tlvs.getByte(SUPPORTED_RSSI_REPORTING);
802             if (isBitSet(rssiReporting, RSSI_REPORTING)) {
803                 builder.hasRssiReportingSupport(true);
804             }
805         } catch (IllegalArgumentException e) {
806             Log.w(TAG, "SUPPORTED_RSSI_REPORTING not found.");
807         }
808 
809         try {
810             byte diagnostics = tlvs.getByte(SUPPORTED_DIAGNOSTICS);
811             if (isBitSet(diagnostics, DIAGNOSTICS)) {
812                 builder.hasDiagnosticsSupport(true);
813             }
814         } catch (IllegalArgumentException e) {
815             Log.w(TAG, "SUPPORTED_DIAGNOSTICS not found.");
816         }
817 
818         try {
819             byte[] rangeDataNtfConfigUciBytes = tlvs.getByteArray(SUPPORTED_RANGE_DATA_NTF_CONFIG);
820             int rangeDataNtfConfigUci =
821                     new BigInteger(TlvUtil.getReverseBytes(rangeDataNtfConfigUciBytes)).intValue();
822             EnumSet<FiraParams.RangeDataNtfConfigCapabilityFlag> rangeDataNtfConfigCapabilityFlag =
823                     EnumSet.noneOf(FiraParams.RangeDataNtfConfigCapabilityFlag.class);
824             if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_ENABLE)) {
825                 rangeDataNtfConfigCapabilityFlag.add(
826                         FiraParams.RangeDataNtfConfigCapabilityFlag
827                                 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE);
828             }
829             if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_DISABLE)) {
830                 rangeDataNtfConfigCapabilityFlag.add(
831                         FiraParams.RangeDataNtfConfigCapabilityFlag
832                                 .HAS_RANGE_DATA_NTF_CONFIG_DISABLE);
833             }
834             if (isBitSet(rangeDataNtfConfigUci,
835                     RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG)) {
836                 rangeDataNtfConfigCapabilityFlag.add(
837                         FiraParams.RangeDataNtfConfigCapabilityFlag
838                                 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG);
839             }
840             if (isBitSet(rangeDataNtfConfigUci,
841                     RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG)) {
842                 rangeDataNtfConfigCapabilityFlag.add(
843                         FiraParams.RangeDataNtfConfigCapabilityFlag
844                                 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG);
845             }
846             if (isBitSet(rangeDataNtfConfigUci,
847                     RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG)) {
848                 rangeDataNtfConfigCapabilityFlag.add(
849                         FiraParams.RangeDataNtfConfigCapabilityFlag
850                                 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG);
851             }
852             if (isBitSet(rangeDataNtfConfigUci,
853                     RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG)) {
854                 rangeDataNtfConfigCapabilityFlag.add(
855                         FiraParams.RangeDataNtfConfigCapabilityFlag
856                                 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG);
857             }
858             if (isBitSet(rangeDataNtfConfigUci,
859                     RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG)) {
860                 rangeDataNtfConfigCapabilityFlag.add(
861                         FiraParams.RangeDataNtfConfigCapabilityFlag
862                                 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG);
863             }
864             if (isBitSet(rangeDataNtfConfigUci,
865                     RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG)) {
866                 rangeDataNtfConfigCapabilityFlag.add(
867                         FiraParams.RangeDataNtfConfigCapabilityFlag
868                                 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG);
869             }
870             builder.setRangeDataNtfConfigCapabilities(rangeDataNtfConfigCapabilityFlag);
871         } catch (IllegalArgumentException e) {
872             Log.w(TAG, "SUPPORTED_RANGE_DATA_NTF_CONFIG not found.");
873         }
874         return builder.build();
875     }
876 }
877