• 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 UUID uuid;
54         public UUID uuid_mask;
55         public String name;
56         public int company;
57         public int company_mask;
58         public byte[] data;
59         public byte[] data_mask;
60     }
61 
62     private Set<Entry> mEntries = new HashSet<Entry>();
63 
addDeviceAddress(String address, byte type)64     void addDeviceAddress(String address, byte type) {
65         Entry entry = new Entry();
66         entry.type = TYPE_DEVICE_ADDRESS;
67         entry.address = address;
68         entry.addr_type = type;
69         mEntries.add(entry);
70     }
71 
addServiceChanged()72     void addServiceChanged() {
73         Entry entry = new Entry();
74         entry.type = TYPE_SERVICE_DATA_CHANGED;
75         mEntries.add(entry);
76     }
77 
addUuid(UUID uuid)78     void addUuid(UUID uuid) {
79         Entry entry = new Entry();
80         entry.type = TYPE_SERVICE_UUID;
81         entry.uuid = uuid;
82         entry.uuid_mask = new UUID(0, 0);
83         mEntries.add(entry);
84     }
85 
addUuid(UUID uuid, UUID uuidMask)86     void addUuid(UUID uuid, UUID uuidMask) {
87         Entry entry = new Entry();
88         entry.type = TYPE_SERVICE_UUID;
89         entry.uuid = uuid;
90         entry.uuid_mask = uuidMask;
91         mEntries.add(entry);
92     }
93 
addSolicitUuid(UUID uuid)94     void addSolicitUuid(UUID uuid) {
95         Entry entry = new Entry();
96         entry.type = TYPE_SOLICIT_UUID;
97         entry.uuid = uuid;
98         mEntries.add(entry);
99     }
100 
addName(String name)101     void addName(String name) {
102         Entry entry = new Entry();
103         entry.type = TYPE_LOCAL_NAME;
104         entry.name = name;
105         mEntries.add(entry);
106     }
107 
addManufacturerData(int company, byte[] data)108     void addManufacturerData(int company, byte[] data) {
109         Entry entry = new Entry();
110         entry.type = TYPE_MANUFACTURER_DATA;
111         entry.company = company;
112         entry.company_mask = 0xFFFF;
113         entry.data = data;
114         entry.data_mask = new byte[data.length];
115         Arrays.fill(entry.data_mask, (byte) 0xFF);
116         mEntries.add(entry);
117     }
118 
addManufacturerData(int company, int companyMask, byte[] data, byte[] dataMask)119     void addManufacturerData(int company, int companyMask, byte[] data, byte[] dataMask) {
120         Entry entry = new Entry();
121         entry.type = TYPE_MANUFACTURER_DATA;
122         entry.company = company;
123         entry.company_mask = companyMask;
124         entry.data = data;
125         entry.data_mask = dataMask;
126         mEntries.add(entry);
127     }
128 
addServiceData(byte[] data, byte[] dataMask)129     void addServiceData(byte[] data, byte[] dataMask) {
130         Entry entry = new Entry();
131         entry.type = TYPE_SERVICE_DATA;
132         entry.data = data;
133         entry.data_mask = dataMask;
134         mEntries.add(entry);
135     }
136 
pop()137     Entry pop() {
138         if (mEntries.isEmpty()) {
139             return null;
140         }
141         Iterator<Entry> iterator = mEntries.iterator();
142         Entry entry = iterator.next();
143         iterator.remove();
144         return entry;
145     }
146 
147     /**
148      * Compute feature selection based on the filters presented.
149      */
getFeatureSelection()150     int getFeatureSelection() {
151         int selc = 0;
152         for (Entry entry : mEntries) {
153             selc |= (1 << entry.type);
154         }
155         return selc;
156     }
157 
toArray()158     ScanFilterQueue.Entry[] toArray() {
159         return mEntries.toArray(new ScanFilterQueue.Entry[mEntries.size()]);
160     }
161 
162     /**
163      * Add ScanFilter to scan filter queue.
164      */
addScanFilter(ScanFilter filter)165     void addScanFilter(ScanFilter filter) {
166         if (filter == null) {
167             return;
168         }
169         if (filter.getDeviceName() != null) {
170             addName(filter.getDeviceName());
171         }
172         if (filter.getDeviceAddress() != null) {
173             addDeviceAddress(filter.getDeviceAddress(), DEVICE_TYPE_ALL);
174         }
175         if (filter.getServiceUuid() != null) {
176             if (filter.getServiceUuidMask() == null) {
177                 addUuid(filter.getServiceUuid().getUuid());
178             } else {
179                 addUuid(filter.getServiceUuid().getUuid(), filter.getServiceUuidMask().getUuid());
180             }
181         }
182         if (filter.getManufacturerData() != null) {
183             if (filter.getManufacturerDataMask() == null) {
184                 addManufacturerData(filter.getManufacturerId(), filter.getManufacturerData());
185             } else {
186                 addManufacturerData(filter.getManufacturerId(), 0xFFFF,
187                         filter.getManufacturerData(), filter.getManufacturerDataMask());
188             }
189         }
190         if (filter.getServiceDataUuid() != null && filter.getServiceData() != null) {
191             ParcelUuid serviceDataUuid = filter.getServiceDataUuid();
192             byte[] serviceData = filter.getServiceData();
193             byte[] serviceDataMask = filter.getServiceDataMask();
194             if (serviceDataMask == null) {
195                 serviceDataMask = new byte[serviceData.length];
196                 Arrays.fill(serviceDataMask, (byte) 0xFF);
197             }
198             serviceData = concate(serviceDataUuid, serviceData);
199             serviceDataMask = concate(serviceDataUuid, serviceDataMask);
200             if (serviceData != null && serviceDataMask != null) {
201                 addServiceData(serviceData, serviceDataMask);
202             }
203         }
204     }
205 
concate(ParcelUuid serviceDataUuid, byte[] serviceData)206     private byte[] concate(ParcelUuid serviceDataUuid, byte[] serviceData) {
207         byte[] uuid = BluetoothUuid.uuidToBytes(serviceDataUuid);
208 
209         int dataLen = uuid.length + (serviceData == null ? 0 : serviceData.length);
210         // If data is too long, don't add it to hardware scan filter.
211         if (dataLen > MAX_LEN_PER_FIELD) {
212             return null;
213         }
214         byte[] concated = new byte[dataLen];
215         System.arraycopy(uuid, 0, concated, 0, uuid.length);
216         if (serviceData != null) {
217             System.arraycopy(serviceData, 0, concated, uuid.length, serviceData.length);
218         }
219         return concated;
220     }
221 }
222