• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 byte array.
51      */
toString(byte[] data)52     static <T> String toString(byte[] data) {
53         if (data == null) {
54             return "null";
55         }
56         if (data.length == 0) {
57             return "{}";
58         }
59         StringBuilder buffer = new StringBuilder();
60         buffer.append('{');
61         for (int i = 0; i < data.length; i++) {
62             buffer.append(data[i]);
63             if ((i + 1) < data.length) {
64                 buffer.append(", ");
65             }
66         }
67         buffer.append('}');
68         return buffer.toString();
69     }
70 
71     /**
72      * Returns a string composed from a {@link SparseArray}.
73      */
toString(SparseArray<byte[]> array)74     static String toString(SparseArray<byte[]> array) {
75         if (array == null) {
76             return "null";
77         }
78         if (array.size() == 0) {
79             return "{}";
80         }
81         StringBuilder buffer = new StringBuilder();
82         buffer.append('{');
83         for (int i = 0; i < array.size(); ++i) {
84             buffer.append(array.keyAt(i)).append("=").append(Arrays.toString(array.valueAt(i)));
85         }
86         buffer.append('}');
87         return buffer.toString();
88     }
89 
90     /**
91      * Returns a string composed from a {@link Map}.
92      */
toString(Map<T, byte[]> map)93     static <T> String toString(Map<T, byte[]> map) {
94         if (map == null) {
95             return "null";
96         }
97         if (map.isEmpty()) {
98             return "{}";
99         }
100         StringBuilder buffer = new StringBuilder();
101         buffer.append('{');
102         Iterator<Map.Entry<T, byte[]>> it = map.entrySet().iterator();
103         while (it.hasNext()) {
104             Map.Entry<T, byte[]> entry = it.next();
105             Object key = entry.getKey();
106             buffer.append(key).append("=").append(Arrays.toString(map.get(key)));
107             if (it.hasNext()) {
108                 buffer.append(", ");
109             }
110         }
111         buffer.append('}');
112         return buffer.toString();
113     }
114 
115     /**
116      * Check whether two {@link SparseArray} equal.
117      */
equals(SparseArray<byte[]> array, SparseArray<byte[]> otherArray)118     static boolean equals(SparseArray<byte[]> array, SparseArray<byte[]> otherArray) {
119         if (array == otherArray) {
120             return true;
121         }
122         if (array == null || otherArray == null) {
123             return false;
124         }
125         if (array.size() != otherArray.size()) {
126             return false;
127         }
128 
129         // Keys are guaranteed in ascending order when indices are in ascending order.
130         for (int i = 0; i < array.size(); ++i) {
131             if (array.keyAt(i) != otherArray.keyAt(i)
132                     || !Arrays.equals(array.valueAt(i), otherArray.valueAt(i))) {
133                 return false;
134             }
135         }
136         return true;
137     }
138 
139     /**
140      * Check whether two {@link Map} equal.
141      */
equals(Map<T, byte[]> map, Map<T, byte[]> otherMap)142     static <T> boolean equals(Map<T, byte[]> map, Map<T, byte[]> otherMap) {
143         if (map == otherMap) {
144             return true;
145         }
146         if (map == null || otherMap == null) {
147             return false;
148         }
149         if (map.size() != otherMap.size()) {
150             return false;
151         }
152         Set<T> keys = map.keySet();
153         if (!keys.equals(otherMap.keySet())) {
154             return false;
155         }
156         for (T key : keys) {
157             if (!Objects.deepEquals(map.get(key), otherMap.get(key))) {
158                 return false;
159             }
160         }
161         return true;
162     }
163 
164     /**
165      * Ensure Bluetooth is turned on.
166      *
167      * @throws IllegalStateException If {@code adapter} is null or Bluetooth state is not {@link
168      * BluetoothAdapter#STATE_ON}.
169      */
checkAdapterStateOn(BluetoothAdapter adapter)170     static void checkAdapterStateOn(BluetoothAdapter adapter) {
171         if (adapter == null || !adapter.isLeEnabled()) {
172             throw new IllegalStateException("BT Adapter is not turned ON");
173         }
174     }
175 
176     /**
177      * Compares two UUIDs with a UUID mask.
178      *
179      * @param data first {@link #UUID} to compare.
180      * @param uuid second {@link #UUID} to compare.
181      * @param mask mask {@link #UUID}.
182      * @return true if both UUIDs are equals when masked, false otherwise.
183      */
maskedEquals(UUID data, UUID uuid, UUID mask)184     static boolean maskedEquals(UUID data, UUID uuid, UUID mask) {
185         if (mask == null) {
186             return Objects.equals(data, uuid);
187         }
188         return (data.getLeastSignificantBits() & mask.getLeastSignificantBits())
189                 == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits())
190                 && (data.getMostSignificantBits() & mask.getMostSignificantBits())
191                 == (uuid.getMostSignificantBits() & mask.getMostSignificantBits());
192     }
193 }
194