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