Home | History | Annotate | Download | only in gatt
      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.Objects;
     27 import java.util.Set;
     28 import java.util.UUID;
     29 
     30 /**
     31  * Helper class used to manage advertisement package filters.
     32  *
     33  * @hide
     34  */
     35 /* package */class ScanFilterQueue {
     36     public static final int TYPE_DEVICE_ADDRESS = 0;
     37     public static final int TYPE_SERVICE_DATA_CHANGED = 1;
     38     public static final int TYPE_SERVICE_UUID = 2;
     39     public static final int TYPE_SOLICIT_UUID = 3;
     40     public static final int TYPE_LOCAL_NAME = 4;
     41     public static final int TYPE_MANUFACTURER_DATA = 5;
     42     public static final int TYPE_SERVICE_DATA = 6;
     43 
     44     // Max length is 31 - 3(flags) - 2 (one byte for length and one byte for type).
     45     private static final int MAX_LEN_PER_FIELD = 26;
     46 
     47     // Values defined in bluedroid.
     48     private static final byte DEVICE_TYPE_ALL = 2;
     49 
     50     class Entry {
     51         public String address;
     52         public byte addr_type;
     53         public byte type;
     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         @Override
     63         public int hashCode() {
     64             return Objects.hash(address, addr_type, type, uuid, uuid_mask, name, company,
     65                     company_mask, data, data_mask);
     66         }
     67 
     68         @Override
     69         public boolean equals(Object obj) {
     70             if (this == obj) {
     71                 return true;
     72             }
     73             if (obj == null || getClass() != obj.getClass()) {
     74                 return false;
     75             }
     76             Entry other = (Entry) obj;
     77             return Objects.equals(address, other.address) &&
     78                     addr_type == other.addr_type && type == other.type &&
     79                     Objects.equals(uuid, other.uuid) &&
     80                     Objects.equals(uuid_mask, other.uuid_mask) &&
     81                     Objects.equals(name, other.name) &&
     82                             company == other.company && company_mask == other.company_mask &&
     83                     Objects.deepEquals(data, other.data) &&
     84                     Objects.deepEquals(data_mask, other.data_mask);
     85         }
     86     }
     87 
     88     private Set<Entry> mEntries = new HashSet<Entry>();
     89 
     90     void addDeviceAddress(String address, byte type) {
     91         Entry entry = new Entry();
     92         entry.type = TYPE_DEVICE_ADDRESS;
     93         entry.address = address;
     94         entry.addr_type = type;
     95         mEntries.add(entry);
     96     }
     97 
     98     void addServiceChanged() {
     99         Entry entry = new Entry();
    100         entry.type = TYPE_SERVICE_DATA_CHANGED;
    101         mEntries.add(entry);
    102     }
    103 
    104     void addUuid(UUID uuid) {
    105         Entry entry = new Entry();
    106         entry.type = TYPE_SERVICE_UUID;
    107         entry.uuid = uuid;
    108         entry.uuid_mask = new UUID(0, 0);
    109         mEntries.add(entry);
    110     }
    111 
    112     void addUuid(UUID uuid, UUID uuid_mask) {
    113         Entry entry = new Entry();
    114         entry.type = TYPE_SERVICE_UUID;
    115         entry.uuid = uuid;
    116         entry.uuid_mask = uuid_mask;
    117         mEntries.add(entry);
    118     }
    119 
    120     void addSolicitUuid(UUID uuid) {
    121         Entry entry = new Entry();
    122         entry.type = TYPE_SOLICIT_UUID;
    123         entry.uuid = uuid;
    124         mEntries.add(entry);
    125     }
    126 
    127     void addName(String name) {
    128         Entry entry = new Entry();
    129         entry.type = TYPE_LOCAL_NAME;
    130         entry.name = name;
    131         mEntries.add(entry);
    132     }
    133 
    134     void addManufacturerData(int company, byte[] data) {
    135         Entry entry = new Entry();
    136         entry.type = TYPE_MANUFACTURER_DATA;
    137         entry.company = company;
    138         entry.company_mask = 0xFFFF;
    139         entry.data = data;
    140         entry.data_mask = new byte[data.length];
    141         Arrays.fill(entry.data_mask, (byte) 0xFF);
    142         mEntries.add(entry);
    143     }
    144 
    145     void addManufacturerData(int company, int company_mask, byte[] data, byte[] data_mask) {
    146         Entry entry = new Entry();
    147         entry.type = TYPE_MANUFACTURER_DATA;
    148         entry.company = company;
    149         entry.company_mask = company_mask;
    150         entry.data = data;
    151         entry.data_mask = data_mask;
    152         mEntries.add(entry);
    153     }
    154 
    155     void addServiceData(byte[] data, byte[] dataMask) {
    156         Entry entry = new Entry();
    157         entry.type = TYPE_SERVICE_DATA;
    158         entry.data = data;
    159         entry.data_mask = dataMask;
    160         mEntries.add(entry);
    161     }
    162 
    163     Entry pop() {
    164         if (isEmpty()) {
    165             return null;
    166         }
    167         Iterator<Entry> iterator = mEntries.iterator();
    168         Entry entry = iterator.next();
    169         iterator.remove();
    170         return entry;
    171     }
    172 
    173     boolean isEmpty() {
    174         return mEntries.isEmpty();
    175     }
    176 
    177     void clearUuids() {
    178         for (Iterator<Entry> it = mEntries.iterator(); it.hasNext();) {
    179             Entry entry = it.next();
    180             if (entry.type == TYPE_SERVICE_UUID)
    181                 it.remove();
    182         }
    183     }
    184 
    185     void clear() {
    186         mEntries.clear();
    187     }
    188 
    189     /**
    190      * Compute feature selection based on the filters presented.
    191      */
    192     int getFeatureSelection() {
    193         int selc = 0;
    194         for (Entry entry : mEntries) {
    195             selc |= (1 << entry.type);
    196         }
    197         return selc;
    198     }
    199 
    200     /**
    201      * Add ScanFilter to scan filter queue.
    202      */
    203     void addScanFilter(ScanFilter filter) {
    204         if (filter == null)
    205             return;
    206         if (filter.getDeviceName() != null) {
    207             addName(filter.getDeviceName());
    208         }
    209         if (filter.getDeviceAddress() != null) {
    210             addDeviceAddress(filter.getDeviceAddress(), DEVICE_TYPE_ALL);
    211         }
    212         if (filter.getServiceUuid() != null) {
    213             if (filter.getServiceUuidMask() == null) {
    214                 addUuid(filter.getServiceUuid().getUuid());
    215             } else {
    216                 addUuid(filter.getServiceUuid().getUuid(),
    217                         filter.getServiceUuidMask().getUuid());
    218             }
    219         }
    220         if (filter.getManufacturerData() != null) {
    221             if (filter.getManufacturerDataMask() == null) {
    222                 addManufacturerData(filter.getManufacturerId(), filter.getManufacturerData());
    223             } else {
    224                 addManufacturerData(filter.getManufacturerId(), 0xFFFF,
    225                         filter.getManufacturerData(), filter.getManufacturerDataMask());
    226             }
    227         }
    228         if (filter.getServiceDataUuid() != null && filter.getServiceData() != null) {
    229             ParcelUuid serviceDataUuid = filter.getServiceDataUuid();
    230             byte[] serviceData = filter.getServiceData();
    231             byte[] serviceDataMask = filter.getServiceDataMask();
    232             if (serviceDataMask == null) {
    233                 serviceDataMask = new byte[serviceData.length];
    234                 Arrays.fill(serviceDataMask, (byte) 0xFF);
    235             }
    236             serviceData = concate(serviceDataUuid, serviceData);
    237             serviceDataMask = concate(serviceDataUuid, serviceDataMask);
    238             if (serviceData != null && serviceDataMask != null) {
    239                 addServiceData(serviceData, serviceDataMask);
    240             }
    241         }
    242     }
    243 
    244     private byte[] concate(ParcelUuid serviceDataUuid, byte[] serviceData) {
    245         int dataLen = 2 + (serviceData == null ? 0 : serviceData.length);
    246         // If data is too long, don't add it to hardware scan filter.
    247         if (dataLen > MAX_LEN_PER_FIELD) {
    248             return null;
    249         }
    250         byte[] concated = new byte[dataLen];
    251         // Extract 16 bit UUID value.
    252         int uuidValue = BluetoothUuid.getServiceIdentifierFromParcelUuid(
    253                 serviceDataUuid);
    254         // First two bytes are service data UUID in little-endian.
    255         concated[0] = (byte) (uuidValue & 0xFF);
    256         concated[1] = (byte) ((uuidValue >> 8) & 0xFF);
    257         if (serviceData != null) {
    258             System.arraycopy(serviceData, 0, concated, 2, serviceData.length);
    259         }
    260         return concated;
    261     }
    262 }
    263