Home | History | Annotate | Download | only in btservice
      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 
     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