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.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 
     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 
     72     void addServiceChanged() {
     73         Entry entry = new Entry();
     74         entry.type = TYPE_SERVICE_DATA_CHANGED;
     75         mEntries.add(entry);
     76     }
     77 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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      */
    150     int getFeatureSelection() {
    151         int selc = 0;
    152         for (Entry entry : mEntries) {
    153             selc |= (1 << entry.type);
    154         }
    155         return selc;
    156     }
    157 
    158     ScanFilterQueue.Entry[] toArray() {
    159         return mEntries.toArray(new ScanFilterQueue.Entry[mEntries.size()]);
    160     }
    161 
    162     /**
    163      * Add ScanFilter to scan filter queue.
    164      */
    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 
    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