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