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