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.google.uwb.support.fira; 18 19 import static com.android.internal.util.Preconditions.checkArgument; 20 21 import static java.util.Objects.requireNonNull; 22 23 import android.os.PersistableBundle; 24 import android.uwb.RangingSession; 25 import android.uwb.UwbAddress; 26 27 import androidx.annotation.Nullable; 28 29 /** 30 * UWB parameters used to reconfigure a FiRa session. Supports peer adding/removing. 31 * 32 * <p>This is passed as a bundle to the service API {@link RangingSession#reconfigure}. 33 */ 34 public class FiraRangingReconfigureParams extends FiraParams { 35 private static final int BUNDLE_VERSION_1 = 1; 36 private static final int BUNDLE_VERSION_CURRENT = BUNDLE_VERSION_1; 37 38 @Nullable @MulticastListUpdateAction private final Integer mAction; 39 @Nullable private final UwbAddress[] mAddressList; 40 @Nullable private final int[] mSubSessionIdList; 41 42 @Nullable private final Integer mBlockStrideLength; 43 44 @Nullable @RangeDataNtfConfig private final Integer mRangeDataNtfConfig; 45 @Nullable private final Integer mRangeDataProximityNear; 46 @Nullable private final Integer mRangeDataProximityFar; 47 48 private static final String KEY_ACTION = "action"; 49 private static final String KEY_MAC_ADDRESS_MODE = "mac_address_mode"; 50 private static final String KEY_ADDRESS_LIST = "address_list"; 51 private static final String KEY_SUB_SESSION_ID_LIST = "sub_session_id_list"; 52 private static final String KEY_UPDATE_BLOCK_STRIDE_LENGTH = "update_block_stride_length"; 53 private static final String KEY_UPDATE_RANGE_DATA_NTF_CONFIG = "update_range_data_ntf_config"; 54 private static final String KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_NEAR = 55 "update_range_data_proximity_near"; 56 private static final String KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_FAR = 57 "update_range_data_proximity_far"; 58 FiraRangingReconfigureParams( @ullable @ulticastListUpdateAction Integer action, @Nullable UwbAddress[] addressList, @Nullable int[] subSessionIdList, @Nullable Integer blockStrideLength, @Nullable Integer rangeDataNtfConfig, @Nullable Integer rangeDataProximityNear, @Nullable Integer rangeDataProximityFar)59 private FiraRangingReconfigureParams( 60 @Nullable @MulticastListUpdateAction Integer action, 61 @Nullable UwbAddress[] addressList, 62 @Nullable int[] subSessionIdList, 63 @Nullable Integer blockStrideLength, 64 @Nullable Integer rangeDataNtfConfig, 65 @Nullable Integer rangeDataProximityNear, 66 @Nullable Integer rangeDataProximityFar) { 67 mAction = action; 68 mAddressList = addressList; 69 mSubSessionIdList = subSessionIdList; 70 mBlockStrideLength = blockStrideLength; 71 mRangeDataNtfConfig = rangeDataNtfConfig; 72 mRangeDataProximityNear = rangeDataProximityNear; 73 mRangeDataProximityFar = rangeDataProximityFar; 74 } 75 76 @Override getBundleVersion()77 protected int getBundleVersion() { 78 return BUNDLE_VERSION_CURRENT; 79 } 80 81 @Nullable 82 @MulticastListUpdateAction getAction()83 public Integer getAction() { 84 return mAction; 85 } 86 87 @Nullable getAddressList()88 public UwbAddress[] getAddressList() { 89 return mAddressList; 90 } 91 92 @Nullable getSubSessionIdList()93 public int[] getSubSessionIdList() { 94 return mSubSessionIdList; 95 } 96 97 @Nullable getBlockStrideLength()98 public Integer getBlockStrideLength() { 99 return mBlockStrideLength; 100 } 101 102 @Nullable getRangeDataNtfConfig()103 public Integer getRangeDataNtfConfig() { 104 return mRangeDataNtfConfig; 105 } 106 107 @Nullable getRangeDataProximityNear()108 public Integer getRangeDataProximityNear() { 109 return mRangeDataProximityNear; 110 } 111 112 @Nullable getRangeDataProximityFar()113 public Integer getRangeDataProximityFar() { 114 return mRangeDataProximityFar; 115 } 116 117 @Override toBundle()118 public PersistableBundle toBundle() { 119 PersistableBundle bundle = super.toBundle(); 120 if (mAction != null) { 121 requireNonNull(mAddressList); 122 bundle.putInt(KEY_ACTION, mAction); 123 124 long[] addressList = new long[mAddressList.length]; 125 int i = 0; 126 for (UwbAddress address : mAddressList) { 127 addressList[i++] = uwbAddressToLong(address); 128 } 129 int macAddressMode = MAC_ADDRESS_MODE_2_BYTES; 130 if (mAddressList[0].size() == UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH) { 131 macAddressMode = MAC_ADDRESS_MODE_8_BYTES; 132 } 133 bundle.putInt(KEY_MAC_ADDRESS_MODE, macAddressMode); 134 bundle.putLongArray(KEY_ADDRESS_LIST, addressList); 135 bundle.putIntArray(KEY_SUB_SESSION_ID_LIST, mSubSessionIdList); 136 } 137 138 if (mBlockStrideLength != null) { 139 bundle.putInt(KEY_UPDATE_BLOCK_STRIDE_LENGTH, mBlockStrideLength); 140 } 141 142 if (mRangeDataNtfConfig != null) { 143 bundle.putInt(KEY_UPDATE_RANGE_DATA_NTF_CONFIG, mRangeDataNtfConfig); 144 } 145 146 if (mRangeDataProximityNear != null) { 147 bundle.putInt(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_NEAR, mRangeDataProximityNear); 148 } 149 150 if (mRangeDataProximityFar != null) { 151 bundle.putInt(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_FAR, mRangeDataProximityFar); 152 } 153 154 return bundle; 155 } 156 fromBundle(PersistableBundle bundle)157 public static FiraRangingReconfigureParams fromBundle(PersistableBundle bundle) { 158 if (!isCorrectProtocol(bundle)) { 159 throw new IllegalArgumentException("Invalid protocol"); 160 } 161 162 switch (getBundleVersion(bundle)) { 163 case BUNDLE_VERSION_1: 164 return parseVersion1(bundle); 165 166 default: 167 throw new IllegalArgumentException("Invalid bundle version"); 168 } 169 } 170 parseVersion1(PersistableBundle bundle)171 private static FiraRangingReconfigureParams parseVersion1(PersistableBundle bundle) { 172 FiraRangingReconfigureParams.Builder builder = new FiraRangingReconfigureParams.Builder(); 173 if (bundle.containsKey(KEY_ACTION)) { 174 int macAddressMode = bundle.getInt(KEY_MAC_ADDRESS_MODE); 175 int addressByteLength = UwbAddress.SHORT_ADDRESS_BYTE_LENGTH; 176 if (macAddressMode == MAC_ADDRESS_MODE_8_BYTES) { 177 addressByteLength = UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH; 178 } 179 180 long[] addresses = bundle.getLongArray(KEY_ADDRESS_LIST); 181 UwbAddress[] addressList = new UwbAddress[addresses.length]; 182 for (int i = 0; i < addresses.length; i++) { 183 addressList[i] = longToUwbAddress(addresses[i], addressByteLength); 184 } 185 builder.setAction(bundle.getInt(KEY_ACTION)) 186 .setAddressList(addressList) 187 .setSubSessionIdList(bundle.getIntArray(KEY_SUB_SESSION_ID_LIST)); 188 } 189 190 if (bundle.containsKey(KEY_UPDATE_BLOCK_STRIDE_LENGTH)) { 191 builder.setBlockStrideLength(bundle.getInt(KEY_UPDATE_BLOCK_STRIDE_LENGTH)); 192 } 193 194 if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_CONFIG)) { 195 builder.setRangeDataNtfConfig(bundle.getInt(KEY_UPDATE_RANGE_DATA_NTF_CONFIG)); 196 } 197 198 if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_NEAR)) { 199 builder.setRangeDataProximityNear( 200 bundle.getInt(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_NEAR)); 201 } 202 203 if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_FAR)) { 204 builder.setRangeDataProximityFar( 205 bundle.getInt(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_FAR)); 206 } 207 208 return builder.build(); 209 } 210 211 /** Builder */ 212 public static class Builder { 213 @Nullable private Integer mAction = null; 214 @Nullable private UwbAddress[] mAddressList = null; 215 @Nullable private int[] mSubSessionIdList = null; 216 217 @Nullable private Integer mBlockStrideLength = null; 218 219 @Nullable private Integer mRangeDataNtfConfig = null; 220 @Nullable private Integer mRangeDataProximityNear = null; 221 @Nullable private Integer mRangeDataProximityFar = null; 222 setAction( @ulticastListUpdateAction int action)223 public FiraRangingReconfigureParams.Builder setAction( 224 @MulticastListUpdateAction int action) { 225 mAction = action; 226 return this; 227 } 228 setAddressList(UwbAddress[] addressList)229 public FiraRangingReconfigureParams.Builder setAddressList(UwbAddress[] addressList) { 230 mAddressList = addressList; 231 return this; 232 } 233 setSubSessionIdList(int[] subSessionIdList)234 public FiraRangingReconfigureParams.Builder setSubSessionIdList(int[] subSessionIdList) { 235 mSubSessionIdList = subSessionIdList; 236 return this; 237 } 238 setBlockStrideLength(int blockStrideLength)239 public FiraRangingReconfigureParams.Builder setBlockStrideLength(int blockStrideLength) { 240 mBlockStrideLength = blockStrideLength; 241 return this; 242 } 243 setRangeDataNtfConfig(int rangeDataNtfConfig)244 public FiraRangingReconfigureParams.Builder setRangeDataNtfConfig(int rangeDataNtfConfig) { 245 mRangeDataNtfConfig = rangeDataNtfConfig; 246 return this; 247 } 248 setRangeDataProximityNear( int rangeDataProximityNear)249 public FiraRangingReconfigureParams.Builder setRangeDataProximityNear( 250 int rangeDataProximityNear) { 251 mRangeDataProximityNear = rangeDataProximityNear; 252 return this; 253 } 254 setRangeDataProximityFar( int rangeDataProximityFar)255 public FiraRangingReconfigureParams.Builder setRangeDataProximityFar( 256 int rangeDataProximityFar) { 257 mRangeDataProximityFar = rangeDataProximityFar; 258 return this; 259 } 260 checkAddressList()261 private void checkAddressList() { 262 checkArgument(mAddressList != null && mAddressList.length > 0); 263 for (UwbAddress uwbAddress : mAddressList) { 264 requireNonNull(uwbAddress); 265 checkArgument(uwbAddress.size() == UwbAddress.SHORT_ADDRESS_BYTE_LENGTH); 266 } 267 268 checkArgument( 269 mSubSessionIdList == null || mSubSessionIdList.length == mAddressList.length); 270 } 271 build()272 public FiraRangingReconfigureParams build() { 273 if (mAction != null) { 274 checkAddressList(); 275 // Either update the address list or update ranging parameters. Not both. 276 checkArgument( 277 mBlockStrideLength == null 278 && mRangeDataNtfConfig == null 279 && mRangeDataProximityNear == null 280 && mRangeDataProximityFar == null); 281 } else { 282 checkArgument( 283 mBlockStrideLength != null 284 || mRangeDataNtfConfig != null 285 || mRangeDataProximityNear != null 286 || mRangeDataProximityFar != null); 287 } 288 289 return new FiraRangingReconfigureParams( 290 mAction, 291 mAddressList, 292 mSubSessionIdList, 293 mBlockStrideLength, 294 mRangeDataNtfConfig, 295 mRangeDataProximityNear, 296 mRangeDataProximityFar); 297 } 298 } 299 } 300