1 /*
2  * Copyright (C) 2012-2014 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.btservice;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothClass;
21 import android.bluetooth.BluetoothDevice;
22 import android.bluetooth.BluetoothMasInstance;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.os.ParcelUuid;
28 import android.util.Log;
29 
30 import com.android.bluetooth.Utils;
31 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
32 
33 import java.util.concurrent.atomic.AtomicInteger;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.HashMap;
37 import java.util.LinkedList;
38 
39 
40 final class RemoteDevices {
41     private static final boolean DBG = false;
42     private static final String TAG = "BluetoothRemoteDevices";
43 
44 
45     private static BluetoothAdapter mAdapter;
46     private static AdapterService mAdapterService;
47     private static ArrayList<BluetoothDevice> mSdpTracker;
48     private static ArrayList<BluetoothDevice> mSdpMasTracker;
49 
50     private Object mObject = new Object();
51 
52     private static final int UUID_INTENT_DELAY = 6000;
53     private static final int MESSAGE_UUID_INTENT = 1;
54 
55     private static final int MAS_INSTANCE_INTENT_DELAY = 6000;
56     private static final int MESSAGE_MAS_INSTANCE_INTENT = 2;
57 
58     private HashMap<BluetoothDevice, DeviceProperties> mDevices;
59 
RemoteDevices(AdapterService service)60     RemoteDevices(AdapterService service) {
61         mAdapter = BluetoothAdapter.getDefaultAdapter();
62         mAdapterService = service;
63         mSdpTracker = new ArrayList<BluetoothDevice>();
64         mSdpMasTracker = new ArrayList<BluetoothDevice>();
65         mDevices = new HashMap<BluetoothDevice, DeviceProperties>();
66     }
67 
68 
cleanup()69     void cleanup() {
70         if (mSdpTracker !=null)
71             mSdpTracker.clear();
72 
73         if (mSdpMasTracker != null)
74             mSdpMasTracker.clear();
75 
76         if (mDevices != null)
77             mDevices.clear();
78     }
79 
80     @Override
clone()81     public Object clone() throws CloneNotSupportedException {
82         throw new CloneNotSupportedException();
83     }
84 
getDeviceProperties(BluetoothDevice device)85     DeviceProperties getDeviceProperties(BluetoothDevice device) {
86         synchronized (mDevices) {
87             return mDevices.get(device);
88         }
89     }
90 
getDevice(byte[] address)91     BluetoothDevice getDevice(byte[] address) {
92         for (BluetoothDevice dev : mDevices.keySet()) {
93             if (dev.getAddress().equals(Utils.getAddressStringFromByte(address))) {
94                 return dev;
95             }
96         }
97         return null;
98     }
99 
addDeviceProperties(byte[] address)100     DeviceProperties addDeviceProperties(byte[] address) {
101         synchronized (mDevices) {
102             DeviceProperties prop = new DeviceProperties();
103             BluetoothDevice device =
104                     mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
105             prop.mAddress = address;
106             mDevices.put(device, prop);
107             return prop;
108         }
109     }
110 
111     class DeviceProperties {
112         private String mName;
113         private byte[] mAddress;
114         private int mBluetoothClass;
115         private short mRssi;
116         private ParcelUuid[] mUuids;
117         private int mDeviceType;
118         private String mAlias;
119         private int mBondState;
120 
DeviceProperties()121         DeviceProperties() {
122             mBondState = BluetoothDevice.BOND_NONE;
123         }
124 
125         /**
126          * @return the mName
127          */
getName()128         String getName() {
129             synchronized (mObject) {
130                 return mName;
131             }
132         }
133 
134         /**
135          * @return the mClass
136          */
getBluetoothClass()137         int getBluetoothClass() {
138             synchronized (mObject) {
139                 return mBluetoothClass;
140             }
141         }
142 
143         /**
144          * @return the mUuids
145          */
getUuids()146         ParcelUuid[] getUuids() {
147             synchronized (mObject) {
148                 return mUuids;
149             }
150         }
151 
152         /**
153          * @return the mAddress
154          */
getAddress()155         byte[] getAddress() {
156             synchronized (mObject) {
157                 return mAddress;
158             }
159         }
160 
161         /**
162          * @return mRssi
163          */
getRssi()164         short getRssi() {
165             synchronized (mObject) {
166                 return mRssi;
167             }
168         }
169 
170         /**
171          * @return mDeviceType
172          */
getDeviceType()173         int getDeviceType() {
174             synchronized (mObject) {
175                 return mDeviceType;
176             }
177         }
178 
179         /**
180          * @return the mAlias
181          */
getAlias()182         String getAlias() {
183             synchronized (mObject) {
184                 return mAlias;
185             }
186         }
187 
188         /**
189          * @param mAlias the mAlias to set
190          */
setAlias(String mAlias)191         void setAlias(String mAlias) {
192             synchronized (mObject) {
193                 this.mAlias = mAlias;
194                 mAdapterService.setDevicePropertyNative(mAddress,
195                     AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME, mAlias.getBytes());
196             }
197         }
198 
199         /**
200          * @param mBondState the mBondState to set
201          */
setBondState(int mBondState)202         void setBondState(int mBondState) {
203             synchronized (mObject) {
204                 this.mBondState = mBondState;
205                 if (mBondState == BluetoothDevice.BOND_NONE)
206                 {
207                     /* Clearing the Uuids local copy when the device is unpaired. If not cleared,
208                     cachedBluetoothDevice issued a connect using the local cached copy of uuids,
209                     without waiting for the ACTION_UUID intent.
210                     This was resulting in multiple calls to connect().*/
211                     mUuids = null;
212                 }
213             }
214         }
215 
216         /**
217          * @return the mBondState
218          */
getBondState()219         int getBondState() {
220             synchronized (mObject) {
221                 return mBondState;
222             }
223         }
224     }
225 
sendUuidIntent(BluetoothDevice device)226     private void sendUuidIntent(BluetoothDevice device) {
227         DeviceProperties prop = getDeviceProperties(device);
228         Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
229         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
230         intent.putExtra(BluetoothDevice.EXTRA_UUID, prop == null? null: prop.mUuids);
231         mAdapterService.initProfilePriorities(device, prop.mUuids);
232         mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM);
233 
234         //Remove the outstanding UUID request
235         mSdpTracker.remove(device);
236     }
237 
238 
sendMasInstanceIntent(BluetoothDevice device, ArrayList<BluetoothMasInstance> instances)239     private void sendMasInstanceIntent(BluetoothDevice device,
240             ArrayList<BluetoothMasInstance> instances) {
241         Intent intent = new Intent(BluetoothDevice.ACTION_MAS_INSTANCE);
242 
243         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
244         if (instances != null)  intent.putExtra(BluetoothDevice.EXTRA_MAS_INSTANCE, instances);
245         mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM);
246 
247         //Remove the outstanding UUID request
248         mSdpMasTracker.remove(device);
249     }
devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values)250     void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) {
251         Intent intent;
252         byte[] val;
253         int type;
254         BluetoothDevice bdDevice = getDevice(address);
255         DeviceProperties device;
256         if (bdDevice == null) {
257             device = addDeviceProperties(address);
258             bdDevice = getDevice(address);
259         } else {
260             device = getDeviceProperties(bdDevice);
261         }
262 
263         for (int j = 0; j < types.length; j++) {
264             type = types[j];
265             val = values[j];
266             if(val.length <= 0)
267                 errorLog("devicePropertyChangedCallback: bdDevice: " + bdDevice + ", value is empty for type: " + type);
268             else {
269                 synchronized(mObject) {
270                     switch (type) {
271                         case AbstractionLayer.BT_PROPERTY_BDNAME:
272                             device.mName = new String(val);
273                             intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
274                             intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
275                             intent.putExtra(BluetoothDevice.EXTRA_NAME, device.mName);
276                             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
277                             mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
278                             debugLog("Remote Device name is: " + device.mName);
279                             break;
280                         case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME:
281                             if (device.mAlias != null) {
282                                 System.arraycopy(val, 0, device.mAlias, 0, val.length);
283                             }
284                             else {
285                                 device.mAlias = new String(val);
286                             }
287                             break;
288                         case AbstractionLayer.BT_PROPERTY_BDADDR:
289                             device.mAddress = val;
290                             debugLog("Remote Address is:" + Utils.getAddressStringFromByte(val));
291                             break;
292                         case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE:
293                             device.mBluetoothClass =  Utils.byteArrayToInt(val);
294                             intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
295                             intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
296                             intent.putExtra(BluetoothDevice.EXTRA_CLASS,
297                                     new BluetoothClass(device.mBluetoothClass));
298                             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
299                             mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
300                             debugLog("Remote class is:" + device.mBluetoothClass);
301                             break;
302                         case AbstractionLayer.BT_PROPERTY_UUIDS:
303                             int numUuids = val.length/AbstractionLayer.BT_UUID_SIZE;
304                             device.mUuids = Utils.byteArrayToUuid(val);
305                             sendUuidIntent(bdDevice);
306                             break;
307                         case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE:
308                             // The device type from hal layer, defined in bluetooth.h,
309                             // matches the type defined in BluetoothDevice.java
310                             device.mDeviceType = Utils.byteArrayToInt(val);
311                             break;
312                         case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI:
313                             // RSSI from hal is in one byte
314                             device.mRssi = val[0];
315                             break;
316                     }
317                 }
318             }
319         }
320     }
321 
deviceFoundCallback(byte[] address)322     void deviceFoundCallback(byte[] address) {
323         // The device properties are already registered - we can send the intent
324         // now
325         BluetoothDevice device = getDevice(address);
326         debugLog("deviceFoundCallback: Remote Address is:" + device);
327         DeviceProperties deviceProp = getDeviceProperties(device);
328         if (deviceProp == null) {
329             errorLog("Device Properties is null for Device:" + device);
330             return;
331         }
332 
333         Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
334         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
335         intent.putExtra(BluetoothDevice.EXTRA_CLASS,
336                 new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass)));
337         intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
338         intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
339 
340         mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
341     }
342 
aclStateChangeCallback(int status, byte[] address, int newState)343     void aclStateChangeCallback(int status, byte[] address, int newState) {
344         BluetoothDevice device = getDevice(address);
345 
346         if (device == null) {
347             errorLog("aclStateChangeCallback: Device is NULL");
348             return;
349         }
350 
351         DeviceProperties prop = getDeviceProperties(device);
352         if (prop == null) {
353             errorLog("aclStateChangeCallback reported unknown device " + Arrays.toString(address));
354         }
355         Intent intent = null;
356         if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) {
357             intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED);
358             debugLog("aclStateChangeCallback: State:Connected to Device:" + device);
359         } else {
360             intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
361             debugLog("aclStateChangeCallback: State:DisConnected to Device:" + device);
362         }
363         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
364         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
365         mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
366     }
367 
deviceMasInstancesFoundCallback(int status, byte[] address, String[] name, int[] scn, int[] id, int[] msgtype)368     void deviceMasInstancesFoundCallback(int status, byte[] address, String[] name, int[] scn,
369             int[] id, int[] msgtype) {
370         BluetoothDevice device = getDevice(address);
371 
372         if (device == null) {
373             errorLog("deviceMasInstancesFoundCallback: Device is NULL");
374             return;
375         }
376 
377         debugLog("deviceMasInstancesFoundCallback: found " + name.length + " instances");
378 
379         ArrayList<BluetoothMasInstance> instances = new ArrayList<BluetoothMasInstance>();
380 
381         for (int i = 0; i < name.length; i++) {
382             BluetoothMasInstance inst = new BluetoothMasInstance(id[i], name[i],
383                     scn[i], msgtype[i]);
384 
385             debugLog(inst.toString());
386 
387             instances.add(inst);
388         }
389 
390         sendMasInstanceIntent(device, instances);
391     }
392 
fetchUuids(BluetoothDevice device)393     void fetchUuids(BluetoothDevice device) {
394         if (mSdpTracker.contains(device)) return;
395         mSdpTracker.add(device);
396 
397         Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
398         message.obj = device;
399         mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
400 
401         //mAdapterService.getDevicePropertyNative(Utils.getBytesFromAddress(device.getAddress()), AbstractionLayer.BT_PROPERTY_UUIDS);
402         mAdapterService.getRemoteServicesNative(Utils.getBytesFromAddress(device.getAddress()));
403     }
404 
fetchMasInstances(BluetoothDevice device)405     void fetchMasInstances(BluetoothDevice device) {
406         if (mSdpMasTracker.contains(device)) return;
407         mSdpMasTracker.add(device);
408 
409         Message message = mHandler.obtainMessage(MESSAGE_MAS_INSTANCE_INTENT);
410         message.obj = device;
411         mHandler.sendMessageDelayed(message, MAS_INSTANCE_INTENT_DELAY);
412 
413         mAdapterService.getRemoteMasInstancesNative(Utils.getBytesFromAddress(device.getAddress()));
414     }
415 
416     private final Handler mHandler = new Handler() {
417         @Override
418         public void handleMessage(Message msg) {
419             switch (msg.what) {
420             case MESSAGE_UUID_INTENT:
421                 BluetoothDevice device = (BluetoothDevice)msg.obj;
422                 if (device != null) {
423                     sendUuidIntent(device);
424                 }
425                 break;
426             case MESSAGE_MAS_INSTANCE_INTENT:
427                 BluetoothDevice dev = (BluetoothDevice)msg.obj;
428                 if (dev != null) {
429                     sendMasInstanceIntent(dev, null);
430                 }
431                 break;
432             }
433         }
434     };
435 
errorLog(String msg)436     private void errorLog(String msg) {
437         Log.e(TAG, msg);
438     }
439 
debugLog(String msg)440     private void debugLog(String msg) {
441         if (DBG) Log.d(TAG, msg);
442     }
443 
infoLog(String msg)444     private void infoLog(String msg) {
445         if (DBG) Log.i(TAG, msg);
446     }
447 
warnLog(String msg)448     private void warnLog(String msg) {
449         Log.w(TAG, msg);
450     }
451 
452 }
453