1 /* 2 * Copyright 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.nearby.common.bluetooth.fastpair; 18 19 import androidx.annotation.Nullable; 20 21 import java.nio.ByteBuffer; 22 import java.nio.ByteOrder; 23 import java.nio.ShortBuffer; 24 import java.util.Arrays; 25 26 /** Represents a block of bytes, with hashCode and equals. */ 27 public abstract class Bytes { 28 private static final char[] sHexDigits = "0123456789abcdef".toCharArray(); 29 private final byte[] mBytes; 30 31 /** 32 * A logical value consisting of one or more bytes in the given order (little-endian, i.e. 33 * LSO...MSO, or big-endian, i.e. MSO...LSO). E.g. the Fast Pair Model ID is a 3-byte value, 34 * and a Bluetooth device address is a 6-byte value. 35 */ 36 public static class Value extends Bytes { 37 private final ByteOrder mByteOrder; 38 39 /** 40 * Constructor. 41 */ Value(byte[] bytes, ByteOrder byteOrder)42 public Value(byte[] bytes, ByteOrder byteOrder) { 43 super(bytes); 44 this.mByteOrder = byteOrder; 45 } 46 47 /** 48 * Gets bytes. 49 */ getBytes(ByteOrder byteOrder)50 public byte[] getBytes(ByteOrder byteOrder) { 51 return this.mByteOrder.equals(byteOrder) ? getBytes() : reverse(getBytes()); 52 } 53 reverse(byte[] bytes)54 private static byte[] reverse(byte[] bytes) { 55 byte[] reversedBytes = new byte[bytes.length]; 56 for (int i = 0; i < bytes.length; i++) { 57 reversedBytes[i] = bytes[bytes.length - i - 1]; 58 } 59 return reversedBytes; 60 } 61 } 62 Bytes(byte[] bytes)63 Bytes(byte[] bytes) { 64 mBytes = bytes; 65 } 66 toHexString(byte[] bytes)67 private static String toHexString(byte[] bytes) { 68 StringBuilder sb = new StringBuilder(2 * bytes.length); 69 for (byte b : bytes) { 70 sb.append(sHexDigits[(b >> 4) & 0xf]).append(sHexDigits[b & 0xf]); 71 } 72 return sb.toString(); 73 } 74 75 /** Returns 2-byte values in the same order, each using the given byte order. */ toBytes(ByteOrder byteOrder, short... shorts)76 public static byte[] toBytes(ByteOrder byteOrder, short... shorts) { 77 ByteBuffer byteBuffer = ByteBuffer.allocate(shorts.length * 2).order(byteOrder); 78 for (short s : shorts) { 79 byteBuffer.putShort(s); 80 } 81 return byteBuffer.array(); 82 } 83 84 /** Returns the shorts in the same order, each converted using the given byte order. */ toShorts(ByteOrder byteOrder, byte[] bytes)85 static short[] toShorts(ByteOrder byteOrder, byte[] bytes) { 86 ShortBuffer shortBuffer = ByteBuffer.wrap(bytes).order(byteOrder).asShortBuffer(); 87 short[] shorts = new short[shortBuffer.remaining()]; 88 shortBuffer.get(shorts); 89 return shorts; 90 } 91 92 /** @return The bytes. */ getBytes()93 public byte[] getBytes() { 94 return mBytes; 95 } 96 97 @Override equals(@ullable Object o)98 public boolean equals(@Nullable Object o) { 99 if (this == o) { 100 return true; 101 } 102 if (!(o instanceof Bytes)) { 103 return false; 104 } 105 Bytes that = (Bytes) o; 106 return Arrays.equals(mBytes, that.mBytes); 107 } 108 109 @Override hashCode()110 public int hashCode() { 111 return Arrays.hashCode(mBytes); 112 } 113 114 @Override toString()115 public String toString() { 116 return toHexString(mBytes); 117 } 118 } 119