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 */
16package com.android.bluetooth.gatt;
17
18import android.util.Log;
19import java.util.ArrayList;
20import java.util.HashMap;
21import java.util.Iterator;
22import java.util.List;
23import java.util.Map;
24import java.util.UUID;
25
26class 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
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
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
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
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
89    HandleMap() {
90        mEntries = new ArrayList<Entry>();
91        mRequestMap = new HashMap<Integer, Integer>();
92    }
93
94    void clear() {
95        mEntries.clear();
96        mRequestMap.clear();
97    }
98
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
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
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
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
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
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
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
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
172    List<Entry> getEntries() {
173        return mEntries;
174    }
175
176    void addRequest(int requestId, int handle) {
177        mRequestMap.put(requestId, handle);
178    }
179
180    void deleteRequest(int requestId) {
181        mRequestMap.remove(requestId);
182    }
183
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     */
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