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