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