1 /* 2 * Copyright 2024 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.ranging.uwb; 18 19 import static com.google.common.collect.ImmutableList.toImmutableList; 20 21 import android.ranging.RangingCapabilities; 22 import android.ranging.RangingManager; 23 import android.ranging.uwb.UwbAddress; 24 import android.ranging.uwb.UwbRangingCapabilities; 25 26 import com.android.server.ranging.RangingTechnology; 27 import com.android.server.ranging.RangingUtils.Conversions; 28 import com.android.server.ranging.oob.TechnologyHeader; 29 30 import com.google.auto.value.AutoValue; 31 import com.google.common.collect.ImmutableList; 32 33 import java.nio.ByteBuffer; 34 import java.util.Arrays; 35 36 /** Capability data for UWB sent as part of CapabilityResponseMessage. */ 37 @AutoValue 38 public abstract class UwbOobCapabilities implements RangingCapabilities.TechnologyCapabilities { 39 40 /** Size in bytes of all properties when serialized. */ 41 private static final int EXPECTED_SIZE_BYTES = 20; 42 43 // Size in bytes for each properties for serialization/deserialization. 44 private static final int UWB_ADDRESS_SIZE = 2; 45 private static final int CHANNELS_SIZE = 4; 46 private static final int PREAMBLES_SIZE = 4; 47 private static final int CONFIG_IDS_SIZE = 4; 48 private static final int MIN_INTERVAL_SIZE = 2; 49 private static final int MIN_SLOT_SIZE = 1; 50 private static final int DEVICE_ROLE_SIZE = 1; 51 52 private static final int CHANNELS_SHIFT = 0; 53 private static final int PREAMBLES_SHIFT = 1; 54 private static final int CONFIG_IDS_SHIFT = 0; 55 private static final int DEVICE_ROLE_SHIFT = 1; 56 57 /** Returns the size of the object in bytes when serialized. */ getSize()58 public static int getSize() { 59 return EXPECTED_SIZE_BYTES; 60 } 61 62 @Override getTechnology()63 public @RangingManager.RangingTechnology int getTechnology() { 64 return RangingTechnology.UWB.getValue(); 65 } 66 67 /** 68 * Parses the given byte array and returns {@link UwbOobCapabilities} object. Throws {@link 69 * IllegalArgumentException} on invalid input. 70 */ parseBytes(byte[] capabilitiesBytes)71 public static UwbOobCapabilities parseBytes(byte[] capabilitiesBytes) { 72 TechnologyHeader header = TechnologyHeader.parseBytes(capabilitiesBytes); 73 74 if (capabilitiesBytes.length < EXPECTED_SIZE_BYTES) { 75 throw new IllegalArgumentException( 76 String.format( 77 "UwbCapabilities size is %d, expected at least %d", 78 capabilitiesBytes.length, EXPECTED_SIZE_BYTES)); 79 } 80 81 if (capabilitiesBytes.length < header.getSize()) { 82 throw new IllegalArgumentException( 83 String.format( 84 "UwbCapabilities header size field is %d, but the size of the array " 85 + "is %d", 86 header.getSize(), capabilitiesBytes.length)); 87 } 88 89 if (header.getRangingTechnology() != RangingTechnology.UWB) { 90 throw new IllegalArgumentException( 91 String.format( 92 "UwbCapabilities header technology field is %s, expected %s", 93 header.getRangingTechnology(), RangingTechnology.UWB)); 94 } 95 96 int parseCursor = header.getHeaderSize(); 97 98 // Parse UWB Address 99 UwbAddress uwbAddress = 100 UwbAddress.fromBytes( 101 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 102 parseCursor + UWB_ADDRESS_SIZE)); 103 parseCursor += UWB_ADDRESS_SIZE; 104 105 // Parse Supported Channels 106 ImmutableList<Integer> supportedChannels = 107 Conversions.byteArrayToIntList( 108 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 109 parseCursor + CHANNELS_SIZE), 110 CHANNELS_SHIFT); 111 parseCursor += CHANNELS_SIZE; 112 113 // Parse Supported Preamble Indexes 114 ImmutableList<Integer> supportedPreambleIndexes = 115 Conversions.byteArrayToIntList( 116 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 117 parseCursor + PREAMBLES_SIZE), 118 PREAMBLES_SHIFT); 119 parseCursor += PREAMBLES_SIZE; 120 121 // Parse Supported Config Ids 122 ImmutableList<Integer> supportedConfigIds = 123 Conversions.byteArrayToIntList( 124 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 125 parseCursor + CONFIG_IDS_SIZE), 126 CONFIG_IDS_SHIFT); 127 parseCursor += CONFIG_IDS_SIZE; 128 129 // Parse Minimum Ranging Interval Ms 130 int minimumRangingIntervalMs = 131 Conversions.byteArrayToInt( 132 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 133 parseCursor + MIN_INTERVAL_SIZE)); 134 parseCursor += MIN_INTERVAL_SIZE; 135 136 // Parse Minimum Slot Duration Ms 137 int minimumSlotDurationMs = 138 Conversions.byteArrayToInt( 139 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 140 parseCursor + MIN_SLOT_SIZE)); 141 parseCursor += MIN_SLOT_SIZE; 142 143 // Parse Device Role 144 ImmutableList<Integer> deviceRoles = 145 Conversions.byteArrayToIntList( 146 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 147 parseCursor + DEVICE_ROLE_SIZE), 148 DEVICE_ROLE_SHIFT) 149 .stream() 150 .collect(toImmutableList()); 151 parseCursor += DEVICE_ROLE_SIZE; 152 153 return UwbOobCapabilities.builder() 154 .setUwbAddress(uwbAddress) 155 .setSupportedChannels(supportedChannels) 156 .setSupportedConfigIds(supportedConfigIds) 157 .setSupportedPreambleIndexes(supportedPreambleIndexes) 158 .setMinimumRangingIntervalMs(minimumRangingIntervalMs) 159 .setMinimumSlotDurationMs(minimumSlotDurationMs) 160 .setSupportedDeviceRole(deviceRoles) 161 .build(); 162 } 163 164 /** Serializes this {@link UwbOobCapabilities} object to bytes. */ toBytes()165 public final byte[] toBytes() { 166 ByteBuffer byteBuffer = ByteBuffer.allocate(EXPECTED_SIZE_BYTES); 167 byteBuffer 168 .put(RangingTechnology.UWB.toByte()) 169 .put((byte) EXPECTED_SIZE_BYTES) 170 .put(getUwbAddress().getAddressBytes()) 171 .put(Conversions.intListToByteArrayBitmap(getSupportedChannels(), CHANNELS_SIZE, 172 CHANNELS_SHIFT)) 173 .put( 174 Conversions.intListToByteArrayBitmap( 175 getSupportedPreambleIndexes(), PREAMBLES_SIZE, PREAMBLES_SHIFT)) 176 .put( 177 Conversions.intListToByteArrayBitmap( 178 getSupportedConfigIds(), CONFIG_IDS_SIZE, CONFIG_IDS_SHIFT)) 179 .put(Conversions.intToByteArray(getMinimumRangingIntervalMs(), MIN_INTERVAL_SIZE)) 180 .put(Conversions.intToByteArray(getMinimumSlotDurationMs(), MIN_SLOT_SIZE)) 181 .put( 182 Conversions.intListToByteArrayBitmap( 183 getSupportedDeviceRole().stream() 184 .collect(toImmutableList()), 185 DEVICE_ROLE_SIZE, 186 DEVICE_ROLE_SHIFT)); 187 188 return byteBuffer.array(); 189 } 190 fromRangingCapabilities( UwbRangingCapabilities capabilities, UwbAddress address )191 public static UwbOobCapabilities fromRangingCapabilities( 192 UwbRangingCapabilities capabilities, UwbAddress address 193 ) { 194 return UwbOobCapabilities.builder() 195 .setUwbAddress(address) 196 .setSupportedChannels( 197 ImmutableList.copyOf(capabilities.getSupportedChannels())) 198 .setSupportedPreambleIndexes( 199 ImmutableList.copyOf(capabilities.getSupportedPreambleIndexes())) 200 .setSupportedConfigIds( 201 ImmutableList.copyOf(capabilities.getSupportedConfigIds())) 202 .setMinimumRangingIntervalMs( 203 (int) capabilities.getMinimumRangingInterval().toMillis()) 204 .setMinimumSlotDurationMs(capabilities.getSupportedSlotDurations() 205 .stream().min(Integer::compare).get()) 206 .setSupportedDeviceRole(ImmutableList.of( 207 UwbOobConfig.OobDeviceRole.INITIATOR, 208 UwbOobConfig.OobDeviceRole.RESPONDER)) 209 .build(); 210 } 211 212 /** Returns the {@link UwbAddress} of the device. */ getUwbAddress()213 public abstract UwbAddress getUwbAddress(); 214 215 /** Returns a list of supported channels. */ getSupportedChannels()216 public abstract ImmutableList<Integer> getSupportedChannels(); 217 218 /** Returns a list of supported preamble indexes. */ getSupportedPreambleIndexes()219 public abstract ImmutableList<Integer> getSupportedPreambleIndexes(); 220 221 /** Returns a list of supported config Ids. */ getSupportedConfigIds()222 public abstract ImmutableList<Integer> getSupportedConfigIds(); 223 224 /** Returns minimum supported ranging interval in ms. */ getMinimumRangingIntervalMs()225 public abstract int getMinimumRangingIntervalMs(); 226 227 /** Returns minimum supported slot duration in ms. */ getMinimumSlotDurationMs()228 public abstract int getMinimumSlotDurationMs(); 229 230 /** Returns supported device roles. */ getSupportedDeviceRole()231 public abstract ImmutableList<Integer> getSupportedDeviceRole(); 232 233 /** Returns a builder for {@link UwbOobCapabilities}. */ builder()234 public static Builder builder() { 235 return new AutoValue_UwbOobCapabilities.Builder(); 236 } 237 238 /** Builder for {@link UwbOobCapabilities}. */ 239 @AutoValue.Builder 240 public abstract static class Builder { 241 setUwbAddress(UwbAddress uwbAddress)242 public abstract Builder setUwbAddress(UwbAddress uwbAddress); 243 setSupportedChannels(ImmutableList<Integer> supportedChannels)244 public abstract Builder setSupportedChannels(ImmutableList<Integer> supportedChannels); 245 setSupportedPreambleIndexes( ImmutableList<Integer> supportedPreambleIndexes)246 public abstract Builder setSupportedPreambleIndexes( 247 ImmutableList<Integer> supportedPreambleIndexes); 248 setSupportedConfigIds(ImmutableList<Integer> supportedConfigIds)249 public abstract Builder setSupportedConfigIds(ImmutableList<Integer> supportedConfigIds); 250 setMinimumRangingIntervalMs(int minimumRangingIntervalMs)251 public abstract Builder setMinimumRangingIntervalMs(int minimumRangingIntervalMs); 252 setMinimumSlotDurationMs(int minimumSlotDurationMs)253 public abstract Builder setMinimumSlotDurationMs(int minimumSlotDurationMs); 254 setSupportedDeviceRole( ImmutableList<Integer> supportedDeviceRole)255 public abstract Builder setSupportedDeviceRole( 256 ImmutableList<Integer> supportedDeviceRole); 257 build()258 public abstract UwbOobCapabilities build(); 259 } 260 } 261