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