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