RemoteDevices.java revision bdf33c0f7176de2bee64b6488a8327d837599fc8
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.concurrent.atomic.AtomicInteger;
31import java.util.ArrayList;
32import java.util.HashMap;
33
34
35final 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
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
58    void cleanup() {
59        if (mSdpTracker !=null)
60            mSdpTracker.clear();
61
62        if (mDevices != null)
63            mDevices.clear();
64    }
65
66    @Override
67    public Object clone() throws CloneNotSupportedException {
68        throw new CloneNotSupportedException();
69    }
70
71    DeviceProperties getDeviceProperties(BluetoothDevice device) {
72        synchronized (mDevices) {
73            return mDevices.get(device);
74        }
75    }
76
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
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
107        DeviceProperties() {
108            mBondState = BluetoothDevice.BOND_NONE;
109        }
110
111        /**
112         * @return the mName
113         */
114        String getName() {
115            synchronized (mObject) {
116                return mName;
117            }
118        }
119
120        /**
121         * @return the mClass
122         */
123        int getBluetoothClass() {
124            synchronized (mObject) {
125                return mBluetoothClass;
126            }
127        }
128
129        /**
130         * @return the mUuids
131         */
132        ParcelUuid[] getUuids() {
133            synchronized (mObject) {
134                return mUuids;
135            }
136        }
137
138        /**
139         * @return the mAddress
140         */
141        byte[] getAddress() {
142            synchronized (mObject) {
143                return mAddress;
144            }
145        }
146
147        /**
148         * @return mRssi
149         */
150        short getRssi() {
151            synchronized (mObject) {
152                return mRssi;
153            }
154        }
155
156        /**
157         * @return mDeviceType
158         */
159        int getDeviceType() {
160            synchronized (mObject) {
161                return mDeviceType;
162            }
163        }
164
165        /**
166         * @return the mAlias
167         */
168        String getAlias() {
169            synchronized (mObject) {
170                return mAlias;
171            }
172        }
173
174        /**
175         * @param mAlias the mAlias to set
176         */
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         */
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         */
209        int getBondState() {
210            synchronized (mObject) {
211                return mBondState;
212            }
213        }
214    }
215
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
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                            sendUuidIntent(bdDevice);
286                            break;
287                        case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE:
288                            // The device type from hal layer, defined in bluetooth.h,
289                            // matches the type defined in BluetoothDevice.java
290                            device.mDeviceType = Utils.byteArrayToInt(val);
291                            break;
292                        case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI:
293                            // RSSI from hal is in one byte
294                            device.mRssi = val[0];
295                            break;
296                    }
297                }
298            }
299        }
300    }
301
302    void deviceFoundCallback(byte[] address) {
303        // The device properties are already registered - we can send the intent
304        // now
305        BluetoothDevice device = getDevice(address);
306        debugLog("deviceFoundCallback: Remote Address is:" + device);
307        DeviceProperties deviceProp = getDeviceProperties(device);
308        if (deviceProp == null) {
309            errorLog("Device Properties is null for Device:" + device);
310            return;
311        }
312
313        Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
314        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
315        intent.putExtra(BluetoothDevice.EXTRA_CLASS,
316                new BluetoothClass(deviceProp.mBluetoothClass));
317        intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
318        intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
319
320        mAdapterService.sendBroadcastMultiplePermissions(intent,
321                new String[] {AdapterService.BLUETOOTH_PERM,
322                        android.Manifest.permission.ACCESS_COARSE_LOCATION});
323    }
324
325    void aclStateChangeCallback(int status, byte[] address, int newState) {
326        BluetoothDevice device = getDevice(address);
327
328        if (device == null) {
329            errorLog("aclStateChangeCallback: Device is NULL");
330            return;
331        }
332        int state = mAdapterService.getState();
333        Log.e(TAG, "state" + state + "newState" + newState);
334
335        DeviceProperties prop = getDeviceProperties(device);
336        if (prop == null) {
337 //         errorLog("aclStateChangeCallback reported unknown device " + Arrays.toString(address));
338        }
339        Intent intent = null;
340        if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) {
341            if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_ON) {
342                intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED);
343            } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON) {
344                intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_CONNECTED);
345            }
346            debugLog("aclStateChangeCallback: State:Connected to Device:" + device);
347        } else {
348            if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
349                /*Broadcasting PAIRING_CANCEL intent as well in this case*/
350                intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL);
351                intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
352                mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
353            }
354            if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_OFF) {
355                intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
356            } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
357                intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_DISCONNECTED);
358            }
359            debugLog("aclStateChangeCallback: State:DisConnected to Device:" + device);
360        }
361        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
362        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
363        mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
364    }
365
366
367
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
379    private final Handler mHandler = new Handler() {
380        @Override
381        public void handleMessage(Message msg) {
382            switch (msg.what) {
383            case MESSAGE_UUID_INTENT:
384                BluetoothDevice device = (BluetoothDevice)msg.obj;
385                if (device != null) {
386                    sendUuidIntent(device);
387                }
388                break;
389            }
390        }
391    };
392
393    private void errorLog(String msg) {
394        Log.e(TAG, msg);
395    }
396
397    private void debugLog(String msg) {
398        if (DBG) Log.d(TAG, msg);
399    }
400
401    private void infoLog(String msg) {
402        if (DBG) Log.i(TAG, msg);
403    }
404
405    private void warnLog(String msg) {
406        Log.w(TAG, msg);
407    }
408
409}
410