• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 com.android.bluetooth.gatt;
18 
19 import android.bluetooth.BluetoothUuid;
20 import android.bluetooth.le.ScanFilter;
21 import android.os.ParcelUuid;
22 
23 import java.util.Arrays;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.Set;
27 import java.util.UUID;
28 
29 /**
30  * Helper class used to manage advertisement package filters.
31  *
32  * @hide
33  */
34 /* package */class ScanFilterQueue {
35     public static final int TYPE_DEVICE_ADDRESS = 0;
36     public static final int TYPE_SERVICE_DATA_CHANGED = 1;
37     public static final int TYPE_SERVICE_UUID = 2;
38     public static final int TYPE_SOLICIT_UUID = 3;
39     public static final int TYPE_LOCAL_NAME = 4;
40     public static final int TYPE_MANUFACTURER_DATA = 5;
41     public static final int TYPE_SERVICE_DATA = 6;
42 
43     // Max length is 31 - 3(flags) - 2 (one byte for length and one byte for type).
44     private static final int MAX_LEN_PER_FIELD = 26;
45 
46     // Values defined in bluedroid.
47     private static final byte DEVICE_TYPE_ALL = 2;
48 
49     class Entry {
50         public byte type;
51         public String address;
52         public byte addr_type;
53         public byte[] irk;
54         public UUID uuid;
55         public UUID uuid_mask;
56         public String name;
57         public int company;
58         public int company_mask;
59         public byte[] data;
60         public byte[] data_mask;
61     }
62 
63     private Set<Entry> mEntries = new HashSet<Entry>();
64 
addDeviceAddress(String address, byte type, byte[] irk)65     void addDeviceAddress(String address, byte type, byte[] irk) {
66         Entry entry = new Entry();
67         entry.type = TYPE_DEVICE_ADDRESS;
68         entry.address = address;
69         entry.addr_type = type;
70         entry.irk = irk;
71         mEntries.add(entry);
72     }
73 
addServiceChanged()74     void addServiceChanged() {
75         Entry entry = new Entry();
76         entry.type = TYPE_SERVICE_DATA_CHANGED;
77         mEntries.add(entry);
78     }
79 
addUuid(UUID uuid)80     void addUuid(UUID uuid) {
81         Entry entry = new Entry();
82         entry.type = TYPE_SERVICE_UUID;
83         entry.uuid = uuid;
84         entry.uuid_mask = new UUID(0, 0);
85         mEntries.add(entry);
86     }
87 
addUuid(UUID uuid, UUID uuidMask)88     void addUuid(UUID uuid, UUID uuidMask) {
89         Entry entry = new Entry();
90         entry.type = TYPE_SERVICE_UUID;
91         entry.uuid = uuid;
92         entry.uuid_mask = uuidMask;
93         mEntries.add(entry);
94     }
95 
addSolicitUuid(UUID uuid)96     void addSolicitUuid(UUID uuid) {
97         Entry entry = new Entry();
98         entry.type = TYPE_SOLICIT_UUID;
99         entry.uuid = uuid;
100         entry.uuid_mask = new UUID(0, 0);
101         mEntries.add(entry);
102     }
103 
addSolicitUuid(UUID uuid, UUID uuidMask)104     void addSolicitUuid(UUID uuid, UUID uuidMask) {
105         Entry entry = new Entry();
106         entry.type = TYPE_SOLICIT_UUID;
107         entry.uuid = uuid;
108         entry.uuid_mask = uuidMask;
109         mEntries.add(entry);
110     }
111 
addName(String name)112     void addName(String name) {
113         Entry entry = new Entry();
114         entry.type = TYPE_LOCAL_NAME;
115         entry.name = name;
116         mEntries.add(entry);
117     }
118 
addManufacturerData(int company, byte[] data)119     void addManufacturerData(int company, byte[] data) {
120         Entry entry = new Entry();
121         entry.type = TYPE_MANUFACTURER_DATA;
122         entry.company = company;
123         entry.company_mask = 0xFFFF;
124         entry.data = data;
125         entry.data_mask = new byte[data.length];
126         Arrays.fill(entry.data_mask, (byte) 0xFF);
127         mEntries.add(entry);
128     }
129 
addManufacturerData(int company, int companyMask, byte[] data, byte[] dataMask)130     void addManufacturerData(int company, int companyMask, byte[] data, byte[] dataMask) {
131         Entry entry = new Entry();
132         entry.type = TYPE_MANUFACTURER_DATA;
133         entry.company = company;
134         entry.company_mask = companyMask;
135         entry.data = data;
136         entry.data_mask = dataMask;
137         mEntries.add(entry);
138     }
139 
addServiceData(byte[] data, byte[] dataMask)140     void addServiceData(byte[] data, byte[] dataMask) {
141         Entry entry = new Entry();
142         entry.type = TYPE_SERVICE_DATA;
143         entry.data = data;
144         entry.data_mask = dataMask;
145         mEntries.add(entry);
146     }
147 
pop()148     Entry pop() {
149         if (mEntries.isEmpty()) {
150             return null;
151         }
152         Iterator<Entry> iterator = mEntries.iterator();
153         Entry entry = iterator.next();
154         iterator.remove();
155         return entry;
156     }
157 
158     /**
159      * Compute feature selection based on the filters presented.
160      */
getFeatureSelection()161     int getFeatureSelection() {
162         int selc = 0;
163         for (Entry entry : mEntries) {
164             selc |= (1 << entry.type);
165         }
166         return selc;
167     }
168 
toArray()169     ScanFilterQueue.Entry[] toArray() {
170         return mEntries.toArray(new ScanFilterQueue.Entry[mEntries.size()]);
171     }
172 
173     /**
174      * Add ScanFilter to scan filter queue.
175      */
addScanFilter(ScanFilter filter)176     void addScanFilter(ScanFilter filter) {
177         if (filter == null) {
178             return;
179         }
180         if (filter.getDeviceName() != null) {
181             addName(filter.getDeviceName());
182         }
183         if (filter.getDeviceAddress() != null) {
184             byte addressType = (byte) filter.getAddressType();
185             // If addressType == iADDRESS_TYPE_PUBLIC (0) then this is the original
186             // setDeviceAddress(address) API path which provided DEVICE_TYPE_ALL (2) which might map
187             // to the stack value for address type of BTM_BLE_STATIC (2)
188             // Additionally, we shouldn't confuse device type with address type.
189             addDeviceAddress(filter.getDeviceAddress(),
190                     ((addressType == 0) ? DEVICE_TYPE_ALL : addressType), filter.getIrk());
191         }
192         if (filter.getServiceUuid() != null) {
193             if (filter.getServiceUuidMask() == null) {
194                 addUuid(filter.getServiceUuid().getUuid());
195             } else {
196                 addUuid(filter.getServiceUuid().getUuid(), filter.getServiceUuidMask().getUuid());
197             }
198         }
199         if (filter.getServiceSolicitationUuid() != null) {
200             if (filter.getServiceSolicitationUuidMask() == null) {
201                 addSolicitUuid(filter.getServiceSolicitationUuid().getUuid());
202             } else {
203                 addSolicitUuid(filter.getServiceSolicitationUuid().getUuid(),
204                         filter.getServiceSolicitationUuidMask().getUuid());
205             }
206         }
207         if (filter.getManufacturerData() != null) {
208             if (filter.getManufacturerDataMask() == null) {
209                 addManufacturerData(filter.getManufacturerId(), filter.getManufacturerData());
210             } else {
211                 addManufacturerData(filter.getManufacturerId(), 0xFFFF,
212                         filter.getManufacturerData(), filter.getManufacturerDataMask());
213             }
214         }
215         if (filter.getServiceDataUuid() != null && filter.getServiceData() != null) {
216             ParcelUuid serviceDataUuid = filter.getServiceDataUuid();
217             byte[] serviceData = filter.getServiceData();
218             byte[] serviceDataMask = filter.getServiceDataMask();
219             if (serviceDataMask == null) {
220                 serviceDataMask = new byte[serviceData.length];
221                 Arrays.fill(serviceDataMask, (byte) 0xFF);
222             }
223             serviceData = concate(serviceDataUuid, serviceData);
224             serviceDataMask = concate(serviceDataUuid, serviceDataMask);
225             if (serviceData != null && serviceDataMask != null) {
226                 addServiceData(serviceData, serviceDataMask);
227             }
228         }
229     }
230 
concate(ParcelUuid serviceDataUuid, byte[] serviceData)231     private byte[] concate(ParcelUuid serviceDataUuid, byte[] serviceData) {
232         byte[] uuid = BluetoothUuid.uuidToBytes(serviceDataUuid);
233 
234         int dataLen = uuid.length + (serviceData == null ? 0 : serviceData.length);
235         // If data is too long, don't add it to hardware scan filter.
236         if (dataLen > MAX_LEN_PER_FIELD) {
237             return null;
238         }
239         byte[] concated = new byte[dataLen];
240         System.arraycopy(uuid, 0, concated, 0, uuid.length);
241         if (serviceData != null) {
242             System.arraycopy(serviceData, 0, concated, uuid.length, serviceData.length);
243         }
244         return concated;
245     }
246 }
247