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