Home | History | Annotate | Download | only in btservice
      1 /*
      2  * Copyright (C) 2012 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.Context;
     23 import android.content.Intent;
     24 import android.os.Handler;
     25 import android.os.Message;
     26 import android.os.ParcelUuid;
     27 import android.util.Log;
     28 
     29 import com.android.bluetooth.Utils;
     30 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
     31 
     32 import java.util.ArrayList;
     33 import java.util.HashMap;
     34 import java.util.LinkedList;
     35 
     36 
     37 final class RemoteDevices {
     38     private static final boolean DBG = false;
     39     private static final String TAG = "BluetoothRemoteDevices";
     40 
     41 
     42     private static BluetoothAdapter mAdapter;
     43     private static AdapterService mAdapterService;
     44     private static ArrayList<BluetoothDevice> mSdpTracker;
     45 
     46     private Object mObject = new Object();
     47 
     48     private static final int UUID_INTENT_DELAY = 6000;
     49     private static final int MESSAGE_UUID_INTENT = 1;
     50 
     51     private HashMap<BluetoothDevice, DeviceProperties> mDevices;
     52 
     53     RemoteDevices(AdapterService service) {
     54         mAdapter = BluetoothAdapter.getDefaultAdapter();
     55         mAdapterService = service;
     56         mSdpTracker = new ArrayList<BluetoothDevice>();
     57         mDevices = new HashMap<BluetoothDevice, DeviceProperties>();
     58     }
     59 
     60 
     61     void cleanup() {
     62         if (mSdpTracker !=null)
     63             mSdpTracker.clear();
     64 
     65         if (mDevices != null)
     66             mDevices.clear();
     67     }
     68 
     69     public Object Clone() throws CloneNotSupportedException {
     70         throw new CloneNotSupportedException();
     71     }
     72 
     73     DeviceProperties getDeviceProperties(BluetoothDevice device) {
     74         synchronized (mDevices) {
     75             return mDevices.get(device);
     76         }
     77     }
     78 
     79     BluetoothDevice getDevice(byte[] address) {
     80         for (BluetoothDevice dev : mDevices.keySet()) {
     81             if (dev.getAddress().equals(Utils.getAddressStringFromByte(address))) {
     82                 return dev;
     83             }
     84         }
     85         return null;
     86     }
     87 
     88     DeviceProperties addDeviceProperties(byte[] address) {
     89         synchronized (mDevices) {
     90             DeviceProperties prop = new DeviceProperties();
     91             BluetoothDevice device =
     92                     mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
     93             prop.mAddress = address;
     94             mDevices.put(device, prop);
     95             return prop;
     96         }
     97     }
     98 
     99     class DeviceProperties {
    100         private String mName;
    101         private byte[] mAddress;
    102         private int mBluetoothClass;
    103         private short mRssi;
    104         private ParcelUuid[] mUuids;
    105         private int mDeviceType;
    106         private String mAlias;
    107         private int mBondState;
    108 
    109         DeviceProperties() {
    110             mBondState = BluetoothDevice.BOND_NONE;
    111         }
    112 
    113         /**
    114          * @return the mName
    115          */
    116         String getName() {
    117             synchronized (mObject) {
    118                 return mName;
    119             }
    120         }
    121 
    122         /**
    123          * @return the mClass
    124          */
    125         int getBluetoothClass() {
    126             synchronized (mObject) {
    127                 return mBluetoothClass;
    128             }
    129         }
    130 
    131         /**
    132          * @return the mUuids
    133          */
    134         ParcelUuid[] getUuids() {
    135             synchronized (mObject) {
    136                 return mUuids;
    137             }
    138         }
    139 
    140         /**
    141          * @return the mAddress
    142          */
    143         byte[] getAddress() {
    144             synchronized (mObject) {
    145                 return mAddress;
    146             }
    147         }
    148 
    149         /**
    150          * @return mRssi
    151          */
    152         short getRssi() {
    153             synchronized (mObject) {
    154                 return mRssi;
    155             }
    156         }
    157 
    158         /**
    159          * @return mDeviceType
    160          */
    161         int getDeviceType() {
    162             synchronized (mObject) {
    163                 return mDeviceType;
    164             }
    165         }
    166 
    167         /**
    168          * @return the mAlias
    169          */
    170         String getAlias() {
    171             synchronized (mObject) {
    172                 return mAlias;
    173             }
    174         }
    175 
    176         /**
    177          * @param mAlias the mAlias to set
    178          */
    179         void setAlias(String mAlias) {
    180             synchronized (mObject) {
    181                 mAdapterService.setDevicePropertyNative(mAddress,
    182                     AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME, mAlias.getBytes());
    183             }
    184         }
    185 
    186         /**
    187          * @param mBondState the mBondState to set
    188          */
    189         void setBondState(int mBondState) {
    190             synchronized (mObject) {
    191                 this.mBondState = mBondState;
    192                 if (mBondState == BluetoothDevice.BOND_NONE)
    193                 {
    194                     /* Clearing the Uuids local copy when the device is unpaired. If not cleared,
    195                     cachedBluetoothDevice issued a connect using the local cached copy of uuids,
    196                     without waiting for the ACTION_UUID intent.
    197                     This was resulting in multiple calls to connect().*/
    198                     mUuids = null;
    199                 }
    200             }
    201         }
    202 
    203         /**
    204          * @return the mBondState
    205          */
    206         int getBondState() {
    207             synchronized (mObject) {
    208                 return mBondState;
    209             }
    210         }
    211     }
    212 
    213 
    214     private void sendUuidIntent(BluetoothDevice device) {
    215         DeviceProperties prop = getDeviceProperties(device);
    216         Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
    217         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
    218         intent.putExtra(BluetoothDevice.EXTRA_UUID, prop == null? null: prop.mUuids);
    219         mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM);
    220 
    221         //Remove the outstanding UUID request
    222         mSdpTracker.remove(device);
    223     }
    224 
    225     private void sendDisplayPinIntent(byte[] address, int pin) {
    226         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
    227         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address));
    228         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin);
    229         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
    230                     BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN);
    231         mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
    232     }
    233 
    234     void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) {
    235         Intent intent;
    236         byte[] val;
    237         int type;
    238         BluetoothDevice bdDevice = getDevice(address);
    239         DeviceProperties device;
    240         if (bdDevice == null) {
    241             device = addDeviceProperties(address);
    242             bdDevice = getDevice(address);
    243         } else {
    244             device = getDeviceProperties(bdDevice);
    245         }
    246 
    247         for (int j = 0; j < types.length; j++) {
    248             type = types[j];
    249             val = values[j];
    250             if(val.length <= 0)
    251                 errorLog("devicePropertyChangedCallback: bdDevice: " + bdDevice + ", value is empty for type: " + type);
    252             else {
    253                 synchronized(mObject) {
    254                     switch (type) {
    255                         case AbstractionLayer.BT_PROPERTY_BDNAME:
    256                             device.mName = new String(val);
    257                             intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
    258                             intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
    259                             intent.putExtra(BluetoothDevice.EXTRA_NAME, device.mName);
    260                             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    261                             mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
    262                             debugLog("Remote Device name is: " + device.mName);
    263                             break;
    264                         case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME:
    265                             if (device.mAlias != null) {
    266                                 System.arraycopy(val, 0, device.mAlias, 0, val.length);
    267                             }
    268                             else {
    269                                 device.mAlias = new String(val);
    270                             }
    271                             break;
    272                         case AbstractionLayer.BT_PROPERTY_BDADDR:
    273                             device.mAddress = val;
    274                             debugLog("Remote Address is:" + Utils.getAddressStringFromByte(val));
    275                             break;
    276                         case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE:
    277                             device.mBluetoothClass =  Utils.byteArrayToInt(val);
    278                             intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
    279                             intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
    280                             intent.putExtra(BluetoothDevice.EXTRA_CLASS,
    281                                     new BluetoothClass(device.mBluetoothClass));
    282                             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    283                             mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
    284                             debugLog("Remote class is:" + device.mBluetoothClass);
    285                             break;
    286                         case AbstractionLayer.BT_PROPERTY_UUIDS:
    287                             int numUuids = val.length/AbstractionLayer.BT_UUID_SIZE;
    288                             device.mUuids = Utils.byteArrayToUuid(val);
    289                             sendUuidIntent(bdDevice);
    290                             break;
    291                         case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE:
    292                             // The device type from hal layer, defined in bluetooth.h,
    293                             // matches the type defined in BluetoothDevice.java
    294                             device.mDeviceType = Utils.byteArrayToInt(val);
    295                             break;
    296                         case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI:
    297                             // RSSI from hal is in one byte
    298                             device.mRssi = val[0];
    299                             break;
    300                     }
    301                 }
    302             }
    303         }
    304     }
    305 
    306     void deviceFoundCallback(byte[] address) {
    307         // The device properties are already registered - we can send the intent
    308         // now
    309         BluetoothDevice device = getDevice(address);
    310         debugLog("deviceFoundCallback: Remote Address is:" + device);
    311         DeviceProperties deviceProp = getDeviceProperties(device);
    312         if (deviceProp == null) {
    313             errorLog("Device Properties is null for Device:" + device);
    314             return;
    315         }
    316 
    317         Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
    318         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
    319         intent.putExtra(BluetoothDevice.EXTRA_CLASS,
    320                 new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass)));
    321         intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
    322         intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
    323 
    324         mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
    325     }
    326 
    327     void pinRequestCallback(byte[] address, byte[] name, int cod) {
    328         //TODO(BT): Get wakelock and update name and cod
    329         BluetoothDevice bdDevice = getDevice(address);
    330         if (bdDevice == null) {
    331             addDeviceProperties(address);
    332         }
    333         BluetoothClass btClass = bdDevice.getBluetoothClass();
    334         int btDeviceClass = btClass.getDeviceClass();
    335         if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD ||
    336             btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) {
    337             // Its a keyboard. Follow the HID spec recommendation of creating the
    338             // passkey and displaying it to the user. If the keyboard doesn't follow
    339             // the spec recommendation, check if the keyboard has a fixed PIN zero
    340             // and pair.
    341             //TODO: Add sFixedPinZerosAutoPairKeyboard() and maintain list of devices that have fixed pin
    342             /*if (mAdapterService.isFixedPinZerosAutoPairKeyboard(address)) {
    343                                mAdapterService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
    344                                return;
    345                      }*/
    346             // Generate a variable PIN. This is not truly random but good enough.
    347             int pin = (int) Math.floor(Math.random() * 1000000);
    348             sendDisplayPinIntent(address, pin);
    349             return;
    350         }
    351         infoLog("pinRequestCallback: " + address + " name:" + name + " cod:" +
    352                 cod);
    353         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
    354         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address));
    355         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
    356                 BluetoothDevice.PAIRING_VARIANT_PIN);
    357         mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
    358         return;
    359     }
    360 
    361     void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant,
    362             int passkey) {
    363         //TODO(BT): Get wakelock and update name and cod
    364         BluetoothDevice bdDevice = getDevice(address);
    365         if (bdDevice == null) {
    366             addDeviceProperties(address);
    367         }
    368 
    369         infoLog("sspRequestCallback: " + address + " name: " + name + " cod: " +
    370                 cod + " pairingVariant " + pairingVariant + " passkey: " + passkey);
    371         int variant;
    372         boolean displayPasskey = false;
    373         if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION) {
    374             variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION;
    375             displayPasskey = true;
    376         } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_CONSENT) {
    377             variant = BluetoothDevice.PAIRING_VARIANT_CONSENT;
    378         } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY) {
    379             variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY;
    380         } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_NOTIFICATION) {
    381             variant = BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY;
    382 	    displayPasskey = true;
    383         } else {
    384             errorLog("SSP Pairing variant not present");
    385             return;
    386         }
    387         BluetoothDevice device = getDevice(address);
    388         if (device == null) {
    389            warnLog("Device is not known for:" + Utils.getAddressStringFromByte(address));
    390            addDeviceProperties(address);
    391            device = getDevice(address);
    392         }
    393         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
    394         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
    395         if (displayPasskey) {
    396             intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
    397         }
    398         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant);
    399         mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
    400     }
    401 
    402     void aclStateChangeCallback(int status, byte[] address, int newState) {
    403         BluetoothDevice device = getDevice(address);
    404 
    405         if (device == null) {
    406             errorLog("aclStateChangeCallback: Device is NULL");
    407             return;
    408         }
    409 
    410         Intent intent = null;
    411         if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) {
    412             intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED);
    413             debugLog("aclStateChangeCallback: State:Connected to Device:" + device);
    414         } else {
    415             intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    416             debugLog("aclStateChangeCallback: State:DisConnected to Device:" + device);
    417         }
    418         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
    419         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    420         mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
    421     }
    422 
    423     void fetchUuids(BluetoothDevice device) {
    424         if (mSdpTracker.contains(device)) return;
    425         mSdpTracker.add(device);
    426 
    427         Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
    428         message.obj = device;
    429         mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
    430 
    431         //mAdapterService.getDevicePropertyNative(Utils.getBytesFromAddress(device.getAddress()), AbstractionLayer.BT_PROPERTY_UUIDS);
    432         mAdapterService.getRemoteServicesNative(Utils.getBytesFromAddress(device.getAddress()));
    433     }
    434 
    435     private final Handler mHandler = new Handler() {
    436         @Override
    437         public void handleMessage(Message msg) {
    438             switch (msg.what) {
    439             case MESSAGE_UUID_INTENT:
    440                 BluetoothDevice device = (BluetoothDevice)msg.obj;
    441                 if (device != null) {
    442                     sendUuidIntent(device);
    443                 }
    444                 break;
    445             }
    446         }
    447     };
    448 
    449     private void errorLog(String msg) {
    450         Log.e(TAG, msg);
    451     }
    452 
    453     private void debugLog(String msg) {
    454         if (DBG) Log.d(TAG, msg);
    455     }
    456 
    457     private void infoLog(String msg) {
    458         if (DBG) Log.i(TAG, msg);
    459     }
    460 
    461     private void warnLog(String msg) {
    462         Log.w(TAG, msg);
    463     }
    464 
    465 }
    466