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 android.util.Log;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.UUID;
25 
26 class HandleMap {
27     private static final boolean DBG = GattServiceConfig.DBG;
28     private static final String TAG = GattServiceConfig.TAG_PREFIX + "HandleMap";
29 
30     public static final int TYPE_UNDEFINED = 0;
31     public static final int TYPE_SERVICE = 1;
32     public static final int TYPE_CHARACTERISTIC = 2;
33     public static final int TYPE_DESCRIPTOR = 3;
34 
35     class Entry {
36         int serverIf = 0;
37         int type = TYPE_UNDEFINED;
38         int handle = 0;
39         UUID uuid = null;
40         int instance = 0;
41         int serviceType = 0;
42         int serviceHandle = 0;
43         int charHandle = 0;
44         boolean started = false;
45         boolean advertisePreferred = false;
46 
Entry(int serverIf, int handle, UUID uuid, int serviceType, int instance)47         Entry(int serverIf, int handle, UUID uuid, int serviceType, int instance) {
48             this.serverIf = serverIf;
49             this.type = TYPE_SERVICE;
50             this.handle = handle;
51             this.uuid = uuid;
52             this.instance = instance;
53             this.serviceType = serviceType;
54         }
55 
Entry(int serverIf, int handle, UUID uuid, int serviceType, int instance, boolean advertisePreferred)56         Entry(int serverIf, int handle, UUID uuid, int serviceType, int instance,
57             boolean advertisePreferred) {
58             this.serverIf = serverIf;
59             this.type = TYPE_SERVICE;
60             this.handle = handle;
61             this.uuid = uuid;
62             this.instance = instance;
63             this.serviceType = serviceType;
64             this.advertisePreferred = advertisePreferred;
65         }
66 
Entry(int serverIf, int type, int handle, UUID uuid, int serviceHandle)67         Entry(int serverIf, int type, int handle, UUID uuid, int serviceHandle) {
68             this.serverIf = serverIf;
69             this.type = type;
70             this.handle = handle;
71             this.uuid = uuid;
72             this.serviceHandle = serviceHandle;
73         }
74 
Entry(int serverIf, int type, int handle, UUID uuid, int serviceHandle, int charHandle)75         Entry(int serverIf, int type, int handle, UUID uuid, int serviceHandle, int charHandle) {
76             this.serverIf = serverIf;
77             this.type = type;
78             this.handle = handle;
79             this.uuid = uuid;
80             this.serviceHandle = serviceHandle;
81             this.charHandle = charHandle;
82         }
83     }
84 
85     List<Entry> mEntries = null;
86     Map<Integer, Integer> mRequestMap = null;
87     int mLastCharacteristic = 0;
88 
HandleMap()89     HandleMap() {
90         mEntries = new ArrayList<Entry>();
91         mRequestMap = new HashMap<Integer, Integer>();
92     }
93 
clear()94     void clear() {
95         mEntries.clear();
96         mRequestMap.clear();
97     }
98 
addService(int serverIf, int handle, UUID uuid, int serviceType, int instance, boolean advertisePreferred)99     void addService(int serverIf, int handle, UUID uuid, int serviceType, int instance,
100         boolean advertisePreferred) {
101         mEntries.add(new Entry(serverIf, handle, uuid, serviceType, instance, advertisePreferred));
102     }
103 
addCharacteristic(int serverIf, int handle, UUID uuid, int serviceHandle)104     void addCharacteristic(int serverIf, int handle, UUID uuid, int serviceHandle) {
105         mLastCharacteristic = handle;
106         mEntries.add(new Entry(serverIf, TYPE_CHARACTERISTIC, handle, uuid, serviceHandle));
107     }
108 
addDescriptor(int serverIf, int handle, UUID uuid, int serviceHandle)109     void addDescriptor(int serverIf, int handle, UUID uuid, int serviceHandle) {
110         mEntries.add(new Entry(serverIf, TYPE_DESCRIPTOR, handle, uuid, serviceHandle, mLastCharacteristic));
111     }
112 
setStarted(int serverIf, int handle, boolean started)113     void setStarted(int serverIf, int handle, boolean started) {
114         for(Entry entry : mEntries) {
115             if (entry.type != TYPE_SERVICE ||
116                 entry.serverIf != serverIf ||
117                 entry.handle != handle)
118                 continue;
119 
120             entry.started = started;
121             return;
122         }
123     }
124 
getByHandle(int handle)125     Entry getByHandle(int handle) {
126         for(Entry entry : mEntries) {
127             if (entry.handle == handle)
128                 return entry;
129         }
130         Log.e(TAG, "getByHandle() - Handle " + handle + " not found!");
131         return null;
132     }
133 
getServiceHandle(UUID uuid, int serviceType, int instance)134     int getServiceHandle(UUID uuid, int serviceType, int instance) {
135         for(Entry entry : mEntries) {
136             if (entry.type == TYPE_SERVICE &&
137                 entry.serviceType == serviceType &&
138                 entry.instance == instance &&
139                 entry.uuid.equals(uuid)) {
140                 return entry.handle;
141             }
142         }
143         Log.e(TAG, "getServiceHandle() - UUID " + uuid + " not found!");
144         return 0;
145     }
146 
getCharacteristicHandle(int serviceHandle, UUID uuid, int instance)147     int getCharacteristicHandle(int serviceHandle, UUID uuid, int instance) {
148         for(Entry entry : mEntries) {
149             if (entry.type == TYPE_CHARACTERISTIC &&
150                 entry.serviceHandle == serviceHandle &&
151                 entry.instance == instance &&
152                 entry.uuid.equals(uuid)) {
153                 return entry.handle;
154             }
155         }
156         Log.e(TAG, "getCharacteristicHandle() - Service " + serviceHandle
157                     + ", UUID " + uuid + " not found!");
158         return 0;
159     }
160 
deleteService(int serverIf, int serviceHandle)161     void deleteService(int serverIf, int serviceHandle) {
162         for(Iterator <Entry> it = mEntries.iterator(); it.hasNext();) {
163             Entry entry = it.next();
164             if (entry.serverIf != serverIf) continue;
165 
166             if (entry.handle == serviceHandle ||
167                 entry.serviceHandle == serviceHandle)
168                 it.remove();
169         }
170     }
171 
getEntries()172     List<Entry> getEntries() {
173         return mEntries;
174     }
175 
addRequest(int requestId, int handle)176     void addRequest(int requestId, int handle) {
177         mRequestMap.put(requestId, handle);
178     }
179 
deleteRequest(int requestId)180     void deleteRequest(int requestId) {
181         mRequestMap.remove(requestId);
182     }
183 
getByRequestId(int requestId)184     Entry getByRequestId(int requestId) {
185         Integer handle = mRequestMap.get(requestId);
186         if (handle == null) {
187             Log.e(TAG, "getByRequestId() - Request ID " + requestId + " not found!");
188             return null;
189         }
190         return getByHandle(handle);
191     }
192 
193 
194     /**
195      * Logs debug information.
196      */
dump(StringBuilder sb)197     void dump(StringBuilder sb) {
198         sb.append("  Entries: " + mEntries.size() + "\n");
199         sb.append("  Requests: " + mRequestMap.size() + "\n");
200 
201         for (Entry entry : mEntries) {
202             sb.append("  " + entry.serverIf + ": [" + entry.handle + "] ");
203             switch(entry.type) {
204                 case TYPE_SERVICE:
205                     sb.append("Service " + entry.uuid);
206                     sb.append(", started " + entry.started);
207                     break;
208 
209                 case TYPE_CHARACTERISTIC:
210                     sb.append("  Characteristic " + entry.uuid);
211                     break;
212 
213                 case TYPE_DESCRIPTOR:
214                     sb.append("    Descriptor " + entry.uuid);
215                     break;
216             }
217 
218             sb.append("\n");
219         }
220     }
221 }
222