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