1 /* 2 * Copyright (C) 2014 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.bluetooth.le; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.util.SparseArray; 21 22 import java.util.Arrays; 23 import java.util.Iterator; 24 import java.util.Map; 25 import java.util.Objects; 26 import java.util.Set; 27 import java.util.UUID; 28 29 /** 30 * Helper class for Bluetooth LE utils. 31 * 32 * @hide 33 */ 34 public class BluetoothLeUtils { 35 /** Returns a string composed from a byte array. */ toString(byte[] data)36 static String toString(byte[] data) { 37 if (data == null) { 38 return "null"; 39 } 40 if (data.length == 0) { 41 return "{}"; 42 } 43 StringBuilder buffer = new StringBuilder(); 44 buffer.append('{'); 45 for (int i = 0; i < data.length; i++) { 46 buffer.append(data[i]); 47 if ((i + 1) < data.length) { 48 buffer.append(", "); 49 } 50 } 51 buffer.append('}'); 52 return buffer.toString(); 53 } 54 55 /** Returns a string composed from a {@link SparseArray}. */ toString(SparseArray<byte[]> array)56 static String toString(SparseArray<byte[]> array) { 57 if (array == null) { 58 return "null"; 59 } 60 if (array.size() == 0) { 61 return "{}"; 62 } 63 StringBuilder buffer = new StringBuilder(); 64 buffer.append('{'); 65 for (int i = 0; i < array.size(); ++i) { 66 buffer.append(array.keyAt(i)).append("=").append(Arrays.toString(array.valueAt(i))); 67 } 68 buffer.append('}'); 69 return buffer.toString(); 70 } 71 72 /** Returns a string composed from a {@link Map}. */ toString(Map<T, byte[]> map)73 static <T> String toString(Map<T, byte[]> map) { 74 if (map == null) { 75 return "null"; 76 } 77 if (map.isEmpty()) { 78 return "{}"; 79 } 80 StringBuilder buffer = new StringBuilder(); 81 buffer.append('{'); 82 Iterator<Map.Entry<T, byte[]>> it = map.entrySet().iterator(); 83 while (it.hasNext()) { 84 Map.Entry<T, byte[]> entry = it.next(); 85 Object key = entry.getKey(); 86 buffer.append(key).append("=").append(Arrays.toString(map.get(key))); 87 if (it.hasNext()) { 88 buffer.append(", "); 89 } 90 } 91 buffer.append('}'); 92 return buffer.toString(); 93 } 94 95 /** Check whether two {@link SparseArray} equal. */ equals(SparseArray<byte[]> array, SparseArray<byte[]> otherArray)96 static boolean equals(SparseArray<byte[]> array, SparseArray<byte[]> otherArray) { 97 if (array == otherArray) { 98 return true; 99 } 100 if (array == null || otherArray == null) { 101 return false; 102 } 103 if (array.size() != otherArray.size()) { 104 return false; 105 } 106 107 // Keys are guaranteed in ascending order when indices are in ascending order. 108 for (int i = 0; i < array.size(); ++i) { 109 if (array.keyAt(i) != otherArray.keyAt(i) 110 || !Arrays.equals(array.valueAt(i), otherArray.valueAt(i))) { 111 return false; 112 } 113 } 114 return true; 115 } 116 117 /** Check whether two {@link Map} equal. */ equals(Map<T, byte[]> map, Map<T, byte[]> otherMap)118 static <T> boolean equals(Map<T, byte[]> map, Map<T, byte[]> otherMap) { 119 if (map == otherMap) { 120 return true; 121 } 122 if (map == null || otherMap == null) { 123 return false; 124 } 125 if (map.size() != otherMap.size()) { 126 return false; 127 } 128 Set<T> keys = map.keySet(); 129 if (!keys.equals(otherMap.keySet())) { 130 return false; 131 } 132 for (T key : keys) { 133 if (!Objects.deepEquals(map.get(key), otherMap.get(key))) { 134 return false; 135 } 136 } 137 return true; 138 } 139 140 /** 141 * Ensure Bluetooth is turned on. 142 * 143 * @throws IllegalStateException If {@code adapter} is null or Bluetooth state is not {@link 144 * BluetoothAdapter#STATE_ON}. 145 */ checkAdapterStateOn(BluetoothAdapter adapter)146 static void checkAdapterStateOn(BluetoothAdapter adapter) { 147 if (adapter == null || !adapter.isLeEnabled()) { 148 throw new IllegalStateException("BT Adapter is not turned ON"); 149 } 150 } 151 152 /** 153 * Compares two UUIDs with a UUID mask. 154 * 155 * @param data first {@link #UUID} to compare. 156 * @param uuid second {@link #UUID} to compare. 157 * @param mask mask {@link #UUID}. 158 * @return true if both UUIDs are equals when masked, false otherwise. 159 */ maskedEquals(UUID data, UUID uuid, UUID mask)160 static boolean maskedEquals(UUID data, UUID uuid, UUID mask) { 161 if (mask == null) { 162 return Objects.equals(data, uuid); 163 } 164 return (data.getLeastSignificantBits() & mask.getLeastSignificantBits()) 165 == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits()) 166 && (data.getMostSignificantBits() & mask.getMostSignificantBits()) 167 == (uuid.getMostSignificantBits() & mask.getMostSignificantBits()); 168 } 169 } 170