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 package com.android.bluetooth.gatt;
17 
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.UUID;
21 
22 class ServiceDeclaration {
23     private static final boolean DBG = GattServiceConfig.DBG;
24     private static final String TAG = GattServiceConfig.TAG_PREFIX + "ServiceDeclaration";
25 
26     public static final byte TYPE_UNDEFINED = 0;
27     public static final byte TYPE_SERVICE = 1;
28     public static final byte TYPE_CHARACTERISTIC = 2;
29     public static final byte TYPE_DESCRIPTOR = 3;
30     public static final byte TYPE_INCLUDED_SERVICE = 4;
31 
32     class Entry {
33         byte type = TYPE_UNDEFINED;
34         UUID uuid = null;
35         int instance = 0;
36         int permissions = 0;
37         int properties = 0;
38         int serviceType = 0;
39         int serviceHandle = 0;
40         boolean advertisePreferred = false;
41 
Entry(UUID uuid, int serviceType, int instance)42         Entry(UUID uuid, int serviceType, int instance) {
43             this.type = TYPE_SERVICE;
44             this.uuid = uuid;
45             this.instance = instance;
46             this.serviceType = serviceType;
47         }
48 
Entry(UUID uuid, int serviceType, int instance, boolean advertisePreferred)49         Entry(UUID uuid, int serviceType, int instance, boolean advertisePreferred) {
50             this.type = TYPE_SERVICE;
51             this.uuid = uuid;
52             this.instance = instance;
53             this.serviceType = serviceType;
54             this.advertisePreferred = advertisePreferred;
55         }
56 
Entry(UUID uuid, int properties, int permissions, int instance)57         Entry(UUID uuid, int properties, int permissions, int instance) {
58             this.type = TYPE_CHARACTERISTIC;
59             this.uuid = uuid;
60             this.instance = instance;
61             this.permissions = permissions;
62             this.properties = properties;
63         }
64 
Entry(UUID uuid, int permissions)65         Entry(UUID uuid, int permissions) {
66             this.type = TYPE_DESCRIPTOR;
67             this.uuid = uuid;
68             this.permissions = permissions;
69         }
70     }
71 
72     // guards access to mEntries and mNumHandles in order to make this class thread-safe
73     private final Object mLock = new Object();
74     private final List<Entry> mEntries = new ArrayList<>();
75     private int mNumHandles = 0;
76 
addService(UUID uuid, int serviceType, int instance, int minHandles, boolean advertisePreferred)77     void addService(UUID uuid, int serviceType, int instance, int minHandles,
78             boolean advertisePreferred) {
79         synchronized (mLock) {
80             mEntries.add(new Entry(uuid, serviceType, instance, advertisePreferred));
81             if (minHandles == 0) {
82                 ++mNumHandles;
83             } else {
84                 mNumHandles = minHandles;
85             }
86         }
87     }
88 
addIncludedService(UUID uuid, int serviceType, int instance)89     void addIncludedService(UUID uuid, int serviceType, int instance) {
90         Entry entry = new Entry(uuid, serviceType, instance);
91         entry.type = TYPE_INCLUDED_SERVICE;
92         synchronized (mLock) {
93             mEntries.add(entry);
94             ++mNumHandles;
95         }
96     }
97 
addCharacteristic(UUID uuid, int properties, int permissions)98     void addCharacteristic(UUID uuid, int properties, int permissions) {
99         synchronized (mLock) {
100             mEntries.add(new Entry(uuid, properties, permissions, 0 /*instance*/));
101             mNumHandles += 2;
102         }
103     }
104 
addDescriptor(UUID uuid, int permissions)105     void addDescriptor(UUID uuid, int permissions) {
106         synchronized (mLock) {
107             mEntries.add(new Entry(uuid, permissions));
108             ++mNumHandles;
109         }
110     }
111 
getNext()112     Entry getNext() {
113         synchronized (mLock) {
114             if (mEntries.isEmpty()) return null;
115             Entry entry = mEntries.get(0);
116             mEntries.remove(0);
117             return entry;
118         }
119     }
120 
isServiceAdvertisePreferred(UUID uuid)121     boolean isServiceAdvertisePreferred(UUID uuid) {
122         synchronized (mLock) {
123             for (Entry entry : mEntries) {
124                 if (entry.uuid.equals(uuid)) {
125                     return entry.advertisePreferred;
126                 }
127             }
128             return false;
129         }
130     }
131 
getNumHandles()132     int getNumHandles() {
133         synchronized (mLock) {
134             return mNumHandles;
135         }
136     }
137 }
138