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