summaryrefslogtreecommitdiff
path: root/framework/java/android/bluetooth/BluetoothUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothUtils.java')
-rw-r--r--framework/java/android/bluetooth/BluetoothUtils.java130
1 files changed, 130 insertions, 0 deletions
diff --git a/framework/java/android/bluetooth/BluetoothUtils.java b/framework/java/android/bluetooth/BluetoothUtils.java
index 705732f526..c1d66c5a8f 100644
--- a/framework/java/android/bluetooth/BluetoothUtils.java
+++ b/framework/java/android/bluetooth/BluetoothUtils.java
@@ -17,13 +17,19 @@
package android.bluetooth;
import android.os.UserHandle;
+import android.util.Log;
import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* {@hide}
*/
public final class BluetoothUtils {
+ private static final String TAG = "BluetoothUtils";
+
/**
* This utility class cannot be instantiated
*/
@@ -45,4 +51,128 @@ public final class BluetoothUtils {
* Match with UserHandl.NULL but accessible inside bluetooth package
*/
public static final UserHandle USER_HANDLE_NULL = UserHandle.of(-10000);
+
+ static class TypeValueEntry {
+ private final int mType;
+ private final byte[] mValue;
+
+ TypeValueEntry(int type, byte[] value) {
+ mType = type;
+ mValue = value;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public byte[] getValue() {
+ return mValue;
+ }
+ }
+
+ // Helper method to extract bytes from byte array.
+ private static byte[] extractBytes(byte[] rawBytes, int start, int length) {
+ int remainingLength = rawBytes.length - start;
+ if (remainingLength < length) {
+ Log.w(TAG, "extractBytes() remaining length " + remainingLength
+ + " is less than copying length " + length + ", array length is "
+ + rawBytes.length + " start is " + start);
+ return null;
+ }
+ byte[] bytes = new byte[length];
+ System.arraycopy(rawBytes, start, bytes, 0, length);
+ return bytes;
+ }
+
+ /**
+ * Parse Length Value Entry from raw bytes
+ *
+ * The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18.
+ *
+ * @param rawBytes raw bytes of Length-Value-Entry array
+ * @hide
+ */
+ public static List<TypeValueEntry> parseLengthTypeValueBytes(byte[] rawBytes) {
+ if (rawBytes == null) {
+ return Collections.emptyList();
+ }
+ if (rawBytes.length == 0) {
+ return Collections.emptyList();
+ }
+
+ int currentPos = 0;
+ List<TypeValueEntry> result = new ArrayList<>();
+ while (currentPos < rawBytes.length) {
+ // length is unsigned int.
+ int length = rawBytes[currentPos] & 0xFF;
+ if (length == 0) {
+ break;
+ }
+ currentPos++;
+ if (currentPos >= rawBytes.length) {
+ Log.w(TAG, "parseLtv() no type and value after length, rawBytes length = "
+ + rawBytes.length + ", currentPost = " + currentPos);
+ break;
+ }
+ // Note the length includes the length of the field type itself.
+ int dataLength = length - 1;
+ // fieldType is unsigned int.
+ int type = rawBytes[currentPos] & 0xFF;
+ currentPos++;
+ if (currentPos >= rawBytes.length) {
+ Log.w(TAG, "parseLtv() no value after length, rawBytes length = "
+ + rawBytes.length + ", currentPost = " + currentPos);
+ break;
+ }
+ byte[] value = extractBytes(rawBytes, currentPos, dataLength);
+ if (value == null) {
+ Log.w(TAG, "failed to extract bytes, currentPost = " + currentPos);
+ break;
+ }
+ result.add(new TypeValueEntry(type, value));
+ currentPos += dataLength;
+ }
+ return result;
+ }
+
+ /**
+ * Serialize type value entries to bytes
+ * @param typeValueEntries type value entries
+ * @return serialized type value entries on success, null on failure
+ */
+ public static byte[] serializeTypeValue(List<TypeValueEntry> typeValueEntries) {
+ // Calculate length
+ int length = 0;
+ for (TypeValueEntry entry : typeValueEntries) {
+ // 1 for length and 1 for type
+ length += 2;
+ if ((entry.getType() - (entry.getType() & 0xFF)) != 0) {
+ Log.w(TAG, "serializeTypeValue() type " + entry.getType()
+ + " is out of range of 0-0xFF");
+ return null;
+ }
+ if (entry.getValue() == null) {
+ Log.w(TAG, "serializeTypeValue() value is null");
+ return null;
+ }
+ int lengthValue = entry.getValue().length + 1;
+ if ((lengthValue - (lengthValue & 0xFF)) != 0) {
+ Log.w(TAG, "serializeTypeValue() entry length " + entry.getValue().length
+ + " is not in range of 0 to 254");
+ return null;
+ }
+ length += entry.getValue().length;
+ }
+ byte[] result = new byte[length];
+ int currentPos = 0;
+ for (TypeValueEntry entry : typeValueEntries) {
+ result[currentPos] = (byte) ((entry.getValue().length + 1) & 0xFF);
+ currentPos++;
+ result[currentPos] = (byte) (entry.getType() & 0xFF);
+ currentPos++;
+ System.arraycopy(entry.getValue(), 0, result, currentPos, entry.getValue().length);
+ currentPos += entry.getValue().length;
+ }
+ return result;
+ }
}