1 /*
2  * Copyright (C) 2022 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 androidx.core.uwb.backend.impl.internal;
18 
19 import androidx.annotation.NonNull;
20 import androidx.annotation.Nullable;
21 
22 import com.google.common.base.Objects;
23 import com.google.common.primitives.Longs;
24 import com.google.common.primitives.Shorts;
25 
26 import java.security.SecureRandom;
27 import java.util.Arrays;
28 
29 /**
30  * UWB supports two addressing formats: 16-bit short address or 64-bit extended address, This class
31  * provides a way to support both formats in one class.
32  */
33 public class UwbAddress {
34 
35     public static final int SHORT_ADDRESS_LENGTH = 2;
36     public static final int EXTENDED_ADDRESS_LENGTH = 8;
37 
38     /** SHORT means 16-bit address EXTENDED means 64-bit address */
39     public enum AddressingMode {
40         SHORT,
41         EXTENDED
42     }
43 
44     private final AddressingMode mAddressingMode;
45     private final byte[] mAddressBytes;
46 
UwbAddress(AddressingMode mode, byte[] addressBytes)47     private UwbAddress(AddressingMode mode, byte[] addressBytes) {
48         this.mAddressingMode = mode;
49         this.mAddressBytes = addressBytes;
50     }
51 
52     /** 2 bytes will be converted to short address, 8 bytes to full */
fromBytes(byte[] address)53     public static UwbAddress fromBytes(byte[] address) {
54         if (address.length == SHORT_ADDRESS_LENGTH) {
55             return new UwbAddress(AddressingMode.SHORT, address);
56         }
57 
58         if (address.length == EXTENDED_ADDRESS_LENGTH) {
59             return new UwbAddress(AddressingMode.EXTENDED, address);
60         }
61 
62         throw new IllegalArgumentException(
63                 String.format(
64                         "the address length only can be 2 bytes (SHORT) or 8 bytes (EXTENDED),"
65                                 + " passed in %d bytes",
66                         address.length));
67     }
68 
69     /** This method provides a way to convert short to/from short address bytes */
fromShort(short address)70     public static UwbAddress fromShort(short address) {
71         return new UwbAddress(AddressingMode.SHORT, Shorts.toByteArray(address));
72     }
73 
74     /** Convert the short address to a short */
toShort(UwbAddress address)75     public static short toShort(UwbAddress address) {
76         if (address.getAddressingMode() != AddressingMode.SHORT) {
77             throw new IllegalArgumentException();
78         }
79 
80         return Shorts.fromByteArray(address.mAddressBytes);
81     }
82 
83     /** This method provides a way to convert long to/from extended address bytes */
fromLong(long address)84     public static UwbAddress fromLong(long address) {
85         return new UwbAddress(AddressingMode.EXTENDED, Longs.toByteArray(address));
86     }
87 
88     /** Convert the extended address to a long */
toLong(UwbAddress address)89     public static long toLong(UwbAddress address) {
90         if (address.getAddressingMode() != AddressingMode.EXTENDED) {
91             throw new IllegalArgumentException();
92         }
93 
94         return Longs.fromByteArray(address.mAddressBytes);
95     }
96 
generateRandomByteArray(int len, SecureRandom secureRandom)97     private static byte[] generateRandomByteArray(int len, SecureRandom secureRandom) {
98         byte[] bytes = new byte[len];
99         secureRandom.nextBytes(bytes);
100         return bytes;
101     }
102 
103     /** Get a randomized short address */
getRandomizedShortAddress()104     public static UwbAddress getRandomizedShortAddress() {
105         SecureRandom secureRandom = new SecureRandom();
106         return fromBytes(generateRandomByteArray(SHORT_ADDRESS_LENGTH, secureRandom));
107     }
108 
109     /** Get a randomized extended address */
getRandomizedExtendedAddress()110     public static UwbAddress getRandomizedExtendedAddress() {
111         SecureRandom secureRandom = new SecureRandom();
112         return fromBytes(generateRandomByteArray(EXTENDED_ADDRESS_LENGTH, secureRandom));
113     }
114 
getAddressingMode()115     public AddressingMode getAddressingMode() {
116         return mAddressingMode;
117     }
118 
119     /** Get the address byte array */
toBytes()120     public byte[] toBytes() {
121         return mAddressBytes.clone();
122     }
123 
124     /** How many bytes the address takes */
size()125     public int size() {
126         if (mAddressingMode == AddressingMode.SHORT) {
127             return SHORT_ADDRESS_LENGTH;
128         }
129 
130         return EXTENDED_ADDRESS_LENGTH;
131     }
132 
133     /** return the address in hex format */
toHexString()134     public String toHexString() {
135         StringBuilder stringBuilder = new StringBuilder("0X");
136         for (byte b : mAddressBytes) {
137             stringBuilder.append(String.format("%02X", b));
138         }
139 
140         return stringBuilder.toString();
141     }
142 
143     @NonNull
144     @Override
toString()145     public String toString() {
146         return toHexString();
147     }
148 
149     @Override
equals(@ullable Object obj)150     public boolean equals(@Nullable Object obj) {
151         if (obj instanceof UwbAddress) {
152             UwbAddress that = (UwbAddress) obj;
153             return Objects.equal(mAddressingMode, that.getAddressingMode())
154                     && Arrays.equals(mAddressBytes, that.toBytes());
155         }
156 
157         return false;
158     }
159 
160     @Override
hashCode()161     public int hashCode() {
162         return Objects.hashCode(mAddressingMode, Arrays.hashCode(mAddressBytes));
163     }
164 }
165