1 /* 2 * Copyright (C) 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 android.ranging.uwb; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import com.android.ranging.flags.Flags; 26 27 import java.security.SecureRandom; 28 import java.util.Arrays; 29 30 /** 31 * A class representing a UWB address 32 */ 33 @FlaggedApi(Flags.FLAG_RANGING_STACK_ENABLED) 34 public final class UwbAddress implements Parcelable { 35 public static final int SHORT_ADDRESS_BYTE_LENGTH = 2; 36 public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8; 37 38 private static final byte[] sShortForbiddenUwbAddress = {(byte) 0xFF, (byte) 0xFF}; 39 private static final byte[] sExtendedForbiddenUwbAddress = { 40 (byte) 0xFF, 41 (byte) 0xFF, 42 (byte) 0xFF, 43 (byte) 0xFF, 44 (byte) 0xFF, 45 (byte) 0xFF, 46 (byte) 0xFF, 47 (byte) 0xFF 48 }; 49 50 private final byte[] mAddressBytes; 51 UwbAddress(byte[] address)52 private UwbAddress(byte[] address) { 53 mAddressBytes = address; 54 } 55 56 /** 57 * Create a {@link android.uwb.UwbAddress} from a byte array. 58 * 59 * <p>If the provided array is {@link #SHORT_ADDRESS_BYTE_LENGTH} bytes, a short address is 60 * created. If the provided array is {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes, then an 61 * extended address is created. 62 * 63 * @param address a byte array to convert to a {@link android.uwb.UwbAddress} 64 * @return a {@link android.uwb.UwbAddress} created from the input byte array 65 * @throws IllegalArgumentException when the length is not one of 66 * {@link #SHORT_ADDRESS_BYTE_LENGTH} or {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes 67 */ 68 @NonNull fromBytes(@onNull byte[] address)69 public static UwbAddress fromBytes(@NonNull byte[] address) { 70 if (address.length != SHORT_ADDRESS_BYTE_LENGTH 71 && address.length != EXTENDED_ADDRESS_BYTE_LENGTH) { 72 throw new IllegalArgumentException("Invalid UwbAddress length " + address.length); 73 } 74 return new UwbAddress(address); 75 } 76 77 /** 78 * Generates a new random 2 bytes {@link UwbAddress}. 79 * 80 * @return a new randomly generated {@link UwbAddress}. 81 */ 82 @NonNull createRandomShortAddress()83 public static UwbAddress createRandomShortAddress() { 84 SecureRandom secureRandom = new SecureRandom(); 85 return fromBytes(generateRandomByteArray(SHORT_ADDRESS_BYTE_LENGTH, secureRandom)); 86 } 87 88 /** 89 * Generates a random 8 bytes {@link UwbAddress}. 90 * 91 * @return a randomly generated {@link UwbAddress}. 92 * 93 * @hide Intentionally hidden. 94 */ 95 @NonNull getRandomExtendedAddress()96 public static UwbAddress getRandomExtendedAddress() { 97 SecureRandom secureRandom = new SecureRandom(); 98 return fromBytes(generateRandomByteArray(EXTENDED_ADDRESS_BYTE_LENGTH, secureRandom)); 99 } 100 generateRandomByteArray(int len, SecureRandom secureRandom)101 private static byte[] generateRandomByteArray(int len, SecureRandom secureRandom) { 102 byte[] bytes = new byte[len]; 103 do { 104 secureRandom.nextBytes(bytes); 105 } while (isForbiddenAddress(bytes)); 106 return bytes; 107 } 108 isForbiddenAddress(byte[] address)109 private static boolean isForbiddenAddress(byte[] address) { 110 if (address.length == SHORT_ADDRESS_BYTE_LENGTH) { 111 return Arrays.equals(address, sShortForbiddenUwbAddress); 112 } else { 113 return Arrays.equals(address, sExtendedForbiddenUwbAddress); 114 } 115 } 116 117 118 /** 119 * Get the address as a byte array 120 * 121 * @return the byte representation of this {@link android.uwb.UwbAddress} 122 */ 123 @NonNull getAddressBytes()124 public byte[] getAddressBytes() { 125 return mAddressBytes; 126 } 127 128 @NonNull 129 @Override toString()130 public String toString() { 131 StringBuilder builder = new StringBuilder("0x"); 132 for (byte addressByte : mAddressBytes) { 133 builder.append(String.format("%02X", addressByte)); 134 } 135 return builder.toString(); 136 } 137 138 @Override equals(@ullable Object obj)139 public boolean equals(@Nullable Object obj) { 140 if (obj instanceof UwbAddress) { 141 return Arrays.equals(mAddressBytes, ((UwbAddress) obj).getAddressBytes()); 142 } 143 return false; 144 } 145 146 @Override hashCode()147 public int hashCode() { 148 return Arrays.hashCode(mAddressBytes); 149 } 150 151 @Override describeContents()152 public int describeContents() { 153 return 0; 154 } 155 156 @Override writeToParcel(@onNull Parcel dest, int flags)157 public void writeToParcel(@NonNull Parcel dest, int flags) { 158 dest.writeInt(mAddressBytes.length); 159 dest.writeByteArray(mAddressBytes); 160 } 161 162 public static final @android.annotation.NonNull Creator<UwbAddress> CREATOR = 163 new Creator<UwbAddress>() { 164 @Override 165 public UwbAddress createFromParcel(Parcel in) { 166 byte[] address = new byte[in.readInt()]; 167 in.readByteArray(address); 168 return UwbAddress.fromBytes(address); 169 } 170 171 @Override 172 public UwbAddress[] newArray(int size) { 173 return new UwbAddress[size]; 174 } 175 }; 176 } 177