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