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.BluetoothA2dp;
     20 import android.bluetooth.BluetoothA2dpSink;
     21 import android.bluetooth.BluetoothAdapter;
     22 import android.bluetooth.BluetoothAvrcpController;
     23 import android.bluetooth.BluetoothDevice;
     24 import android.bluetooth.BluetoothHeadset;
     25 import android.bluetooth.BluetoothHeadsetClient;
     26 import android.bluetooth.BluetoothInputDevice;
     27 import android.bluetooth.BluetoothInputHost;
     28 import android.bluetooth.BluetoothMap;
     29 import android.bluetooth.BluetoothMapClient;
     30 import android.bluetooth.BluetoothPan;
     31 import android.bluetooth.BluetoothPbap;
     32 import android.bluetooth.BluetoothPbapClient;
     33 import android.bluetooth.BluetoothProfile;
     34 import android.bluetooth.BluetoothSap;
     35 import android.content.BroadcastReceiver;
     36 import android.content.Context;
     37 import android.content.Intent;
     38 import android.content.IntentFilter;
     39 import android.os.ParcelUuid;
     40 import android.os.UserHandle;
     41 import android.util.Log;
     42 import android.util.Pair;
     43 
     44 import com.android.bluetooth.Utils;
     45 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
     46 
     47 import java.lang.System;
     48 import java.util.HashMap;
     49 import java.util.concurrent.CopyOnWriteArrayList;
     50 
     51 class AdapterProperties {
     52     private static final boolean DBG = true;
     53     private static final boolean VDBG = false;
     54     private static final String TAG = "BluetoothAdapterProperties";
     55 
     56     private static final long DEFAULT_DISCOVERY_TIMEOUT_MS = 12800;
     57     private static final int BD_ADDR_LEN = 6; // in bytes
     58 
     59     private volatile String mName;
     60     private volatile byte[] mAddress;
     61     private volatile int mBluetoothClass;
     62     private volatile int mScanMode;
     63     private volatile int mDiscoverableTimeout;
     64     private volatile ParcelUuid[] mUuids;
     65     private CopyOnWriteArrayList<BluetoothDevice> mBondedDevices = new CopyOnWriteArrayList<BluetoothDevice>();
     66 
     67     private int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting;
     68     private final HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState =
     69             new HashMap<>();
     70 
     71     private volatile int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
     72     private volatile int mState = BluetoothAdapter.STATE_OFF;
     73 
     74     private AdapterService mService;
     75     private boolean mDiscovering;
     76     private long mDiscoveryEndMs; //< Time (ms since epoch) that discovery ended or will end.
     77     private RemoteDevices mRemoteDevices;
     78     private BluetoothAdapter mAdapter;
     79     //TODO - all hw capabilities to be exposed as a class
     80     private int mNumOfAdvertisementInstancesSupported;
     81     private boolean mRpaOffloadSupported;
     82     private int mNumOfOffloadedIrkSupported;
     83     private int mNumOfOffloadedScanFilterSupported;
     84     private int mOffloadedScanResultStorageBytes;
     85     private int mVersSupported;
     86     private int mTotNumOfTrackableAdv;
     87     private boolean mIsExtendedScanSupported;
     88     private boolean mIsDebugLogSupported;
     89     private boolean mIsActivityAndEnergyReporting;
     90     private boolean mIsLe2MPhySupported;
     91     private boolean mIsLeCodedPhySupported;
     92     private boolean mIsLeExtendedAdvertisingSupported;
     93     private boolean mIsLePeriodicAdvertisingSupported;
     94     private int mLeMaximumAdvertisingDataLength;
     95 
     96     private boolean mReceiverRegistered;
     97     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
     98         @Override
     99         public void onReceive(Context context, Intent intent) {
    100             String action = intent.getAction();
    101             if (action == null) {
    102                 Log.w(TAG, "Received intent with null action");
    103                 return;
    104             }
    105             switch (action) {
    106                 case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
    107                     sendConnectionStateChange(BluetoothProfile.HEADSET, intent);
    108                     break;
    109                 case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
    110                     sendConnectionStateChange(BluetoothProfile.A2DP, intent);
    111                     break;
    112                 case BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED:
    113                     sendConnectionStateChange(BluetoothProfile.HEADSET_CLIENT, intent);
    114                     break;
    115                 case BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED:
    116                     sendConnectionStateChange(BluetoothProfile.A2DP_SINK, intent);
    117                     break;
    118                 case BluetoothInputHost.ACTION_CONNECTION_STATE_CHANGED:
    119                     sendConnectionStateChange(BluetoothProfile.INPUT_HOST, intent);
    120                     break;
    121                 case BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED:
    122                     sendConnectionStateChange(BluetoothProfile.INPUT_DEVICE, intent);
    123                     break;
    124                 case BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED:
    125                     sendConnectionStateChange(BluetoothProfile.AVRCP_CONTROLLER, intent);
    126                     break;
    127                 case BluetoothPan.ACTION_CONNECTION_STATE_CHANGED:
    128                     sendConnectionStateChange(BluetoothProfile.PAN, intent);
    129                     break;
    130                 case BluetoothMap.ACTION_CONNECTION_STATE_CHANGED:
    131                     sendConnectionStateChange(BluetoothProfile.MAP, intent);
    132                     break;
    133                 case BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED:
    134                     sendConnectionStateChange(BluetoothProfile.MAP_CLIENT, intent);
    135                     break;
    136                 case BluetoothSap.ACTION_CONNECTION_STATE_CHANGED:
    137                     sendConnectionStateChange(BluetoothProfile.SAP, intent);
    138                     break;
    139                 case BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED:
    140                     sendConnectionStateChange(BluetoothProfile.PBAP_CLIENT, intent);
    141                     break;
    142                 default:
    143                     Log.w(TAG, "Received unknown intent " + intent);
    144                     break;
    145             }
    146         }
    147     };
    148 
    149     // Lock for all getters and setters.
    150     // If finer grained locking is needer, more locks
    151     // can be added here.
    152     private final Object mObject = new Object();
    153 
    154     public AdapterProperties(AdapterService service) {
    155         mService = service;
    156         mAdapter = BluetoothAdapter.getDefaultAdapter();
    157     }
    158     public void init(RemoteDevices remoteDevices) {
    159         mProfileConnectionState.clear();
    160         mRemoteDevices = remoteDevices;
    161 
    162         IntentFilter filter = new IntentFilter();
    163         filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
    164         filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
    165         filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
    166         filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
    167         filter.addAction(BluetoothInputHost.ACTION_CONNECTION_STATE_CHANGED);
    168         filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
    169         filter.addAction(BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED);
    170         filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
    171         filter.addAction(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
    172         filter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
    173         filter.addAction(BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
    174         filter.addAction(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
    175         mService.registerReceiver(mReceiver, filter);
    176         mReceiverRegistered = true;
    177     }
    178 
    179     public void cleanup() {
    180         mRemoteDevices = null;
    181         mProfileConnectionState.clear();
    182         if (mReceiverRegistered) {
    183             mService.unregisterReceiver(mReceiver);
    184             mReceiverRegistered = false;
    185         }
    186         mService = null;
    187         mBondedDevices.clear();
    188     }
    189 
    190     @Override
    191     public Object clone() throws CloneNotSupportedException {
    192         throw new CloneNotSupportedException();
    193     }
    194 
    195     /**
    196      * @return the mName
    197      */
    198     String getName() {
    199         return mName;
    200     }
    201 
    202     /**
    203      * Set the local adapter property - name
    204      * @param name the name to set
    205      */
    206     boolean setName(String name) {
    207         synchronized (mObject) {
    208             return mService.setAdapterPropertyNative(
    209                     AbstractionLayer.BT_PROPERTY_BDNAME, name.getBytes());
    210         }
    211     }
    212 
    213     /**
    214      * @return the mClass
    215      */
    216     int getBluetoothClass() {
    217         return mBluetoothClass;
    218     }
    219 
    220     /**
    221      * @return the mScanMode
    222      */
    223     int getScanMode() {
    224         return mScanMode;
    225     }
    226 
    227     /**
    228      * Set the local adapter property - scanMode
    229      *
    230      * @param scanMode the ScanMode to set
    231      */
    232     boolean setScanMode(int scanMode) {
    233         synchronized (mObject) {
    234             return mService.setAdapterPropertyNative(
    235                     AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE, Utils.intToByteArray(scanMode));
    236         }
    237     }
    238 
    239     /**
    240      * @return the mUuids
    241      */
    242     ParcelUuid[] getUuids() {
    243         return mUuids;
    244     }
    245 
    246     /**
    247      * @return the mAddress
    248      */
    249     byte[] getAddress() {
    250         return mAddress;
    251     }
    252 
    253     /**
    254      * @param mConnectionState the mConnectionState to set
    255      */
    256     void setConnectionState(int mConnectionState) {
    257         this.mConnectionState = mConnectionState;
    258     }
    259 
    260     /**
    261      * @return the mConnectionState
    262      */
    263     int getConnectionState() {
    264         return mConnectionState;
    265     }
    266 
    267     /**
    268      * @param mState the mState to set
    269      */
    270     void setState(int mState) {
    271         debugLog("Setting state to " + mState);
    272         this.mState = mState;
    273     }
    274 
    275     /**
    276      * @return the mState
    277      */
    278     int getState() {
    279         return mState;
    280     }
    281 
    282     /**
    283      * @return the mNumOfAdvertisementInstancesSupported
    284      */
    285     int getNumOfAdvertisementInstancesSupported() {
    286         return mNumOfAdvertisementInstancesSupported;
    287     }
    288 
    289     /**
    290      * @return the mRpaOffloadSupported
    291      */
    292     boolean isRpaOffloadSupported() {
    293         return mRpaOffloadSupported;
    294     }
    295 
    296     /**
    297      * @return the mNumOfOffloadedIrkSupported
    298      */
    299     int getNumOfOffloadedIrkSupported() {
    300         return mNumOfOffloadedIrkSupported;
    301     }
    302 
    303     /**
    304      * @return the mNumOfOffloadedScanFilterSupported
    305      */
    306     int getNumOfOffloadedScanFilterSupported() {
    307         return mNumOfOffloadedScanFilterSupported;
    308     }
    309 
    310     /**
    311      * @return the mOffloadedScanResultStorageBytes
    312      */
    313     int getOffloadedScanResultStorage() {
    314         return mOffloadedScanResultStorageBytes;
    315     }
    316 
    317     /**
    318      * @return tx/rx/idle activity and energy info
    319      */
    320     boolean isActivityAndEnergyReportingSupported() {
    321         return mIsActivityAndEnergyReporting;
    322     }
    323 
    324     /**
    325      * @return the mIsLe2MPhySupported
    326      */
    327     boolean isLe2MPhySupported() {
    328         return mIsLe2MPhySupported;
    329     }
    330 
    331     /**
    332      * @return the mIsLeCodedPhySupported
    333      */
    334     boolean isLeCodedPhySupported() {
    335         return mIsLeCodedPhySupported;
    336     }
    337 
    338     /**
    339      * @return the mIsLeExtendedAdvertisingSupported
    340      */
    341     boolean isLeExtendedAdvertisingSupported() {
    342         return mIsLeExtendedAdvertisingSupported;
    343     }
    344 
    345     /**
    346      * @return the mIsLePeriodicAdvertisingSupported
    347      */
    348     boolean isLePeriodicAdvertisingSupported() {
    349         return mIsLePeriodicAdvertisingSupported;
    350     }
    351 
    352     /**
    353      * @return the getLeMaximumAdvertisingDataLength
    354      */
    355     int getLeMaximumAdvertisingDataLength() {
    356         return mLeMaximumAdvertisingDataLength;
    357     }
    358 
    359     /**
    360      * @return total number of trackable advertisements
    361      */
    362     int getTotalNumOfTrackableAdvertisements() {
    363         return mTotNumOfTrackableAdv;
    364     }
    365 
    366     /**
    367      * @return the mBondedDevices
    368      */
    369     BluetoothDevice[] getBondedDevices() {
    370         BluetoothDevice[] bondedDeviceList = new BluetoothDevice[0];
    371         try {
    372             bondedDeviceList = mBondedDevices.toArray(bondedDeviceList);
    373         } catch(ArrayStoreException ee) {
    374             errorLog("Error retrieving bonded device array");
    375         }
    376         infoLog("getBondedDevices: length=" + bondedDeviceList.length);
    377         return bondedDeviceList;
    378     }
    379 
    380     // This function shall be invoked from BondStateMachine whenever the bond
    381     // state changes.
    382     void onBondStateChanged(BluetoothDevice device, int state)
    383     {
    384         if (device == null) {
    385             Log.w(TAG, "onBondStateChanged, device is null");
    386             return;
    387         }
    388         try {
    389             byte[] addrByte = Utils.getByteAddress(device);
    390             DeviceProperties prop = mRemoteDevices.getDeviceProperties(device);
    391             if (prop == null)
    392                 prop = mRemoteDevices.addDeviceProperties(addrByte);
    393             prop.setBondState(state);
    394 
    395             if (state == BluetoothDevice.BOND_BONDED) {
    396                 // add if not already in list
    397                 if(!mBondedDevices.contains(device)) {
    398                     debugLog("Adding bonded device:" +  device);
    399                     mBondedDevices.add(device);
    400                 }
    401             } else if (state == BluetoothDevice.BOND_NONE) {
    402                 // remove device from list
    403                 if (mBondedDevices.remove(device))
    404                     debugLog("Removing bonded device:" +  device);
    405                 else
    406                     debugLog("Failed to remove device: " + device);
    407             }
    408         }
    409         catch(Exception ee) {
    410             Log.w(TAG, "onBondStateChanged: Exception ", ee);
    411         }
    412     }
    413 
    414     int getDiscoverableTimeout() {
    415         return mDiscoverableTimeout;
    416     }
    417 
    418     boolean setDiscoverableTimeout(int timeout) {
    419         synchronized (mObject) {
    420             return mService.setAdapterPropertyNative(
    421                     AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT,
    422                     Utils.intToByteArray(timeout));
    423         }
    424     }
    425 
    426     int getProfileConnectionState(int profile) {
    427         synchronized (mObject) {
    428             Pair<Integer, Integer> p = mProfileConnectionState.get(profile);
    429             if (p != null) return p.first;
    430             return BluetoothProfile.STATE_DISCONNECTED;
    431         }
    432     }
    433 
    434     long discoveryEndMillis() {
    435         return mDiscoveryEndMs;
    436     }
    437 
    438     boolean isDiscovering() {
    439         return mDiscovering;
    440     }
    441 
    442     private void sendConnectionStateChange(int profile, Intent connIntent) {
    443         BluetoothDevice device = connIntent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
    444         int prevState = connIntent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
    445         int state = connIntent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
    446         Log.d(TAG,
    447                 "PROFILE_CONNECTION_STATE_CHANGE: profile=" + profile + ", device=" + device + ", "
    448                         + prevState + " -> " + state);
    449         if (!isNormalStateTransition(prevState, state)) {
    450             Log.w(TAG,
    451                     "PROFILE_CONNECTION_STATE_CHANGE: unexpected transition for profile=" + profile
    452                             + ", device=" + device + ", " + prevState + " -> " + state);
    453         }
    454         sendConnectionStateChange(device, profile, state, prevState);
    455     }
    456     void sendConnectionStateChange(BluetoothDevice device, int profile, int state, int prevState) {
    457         if (!validateProfileConnectionState(state) ||
    458                 !validateProfileConnectionState(prevState)) {
    459             // Previously, an invalid state was broadcast anyway,
    460             // with the invalid state converted to -1 in the intent.
    461             // Better to log an error and not send an intent with
    462             // invalid contents or set mAdapterConnectionState to -1.
    463             errorLog("sendConnectionStateChange: invalid state transition " + prevState + " -> "
    464                     + state);
    465             return;
    466         }
    467 
    468         synchronized (mObject) {
    469             updateProfileConnectionState(profile, state, prevState);
    470 
    471             if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
    472                 int newAdapterState = convertToAdapterState(state);
    473                 int prevAdapterState = convertToAdapterState(prevState);
    474                 setConnectionState(newAdapterState);
    475 
    476                 Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
    477                 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
    478                 intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, newAdapterState);
    479                 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, prevAdapterState);
    480                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    481                 Log.d(TAG,
    482                         "ADAPTER_CONNECTION_STATE_CHANGE: " + device + ": " + prevAdapterState
    483                                 + " -> " + newAdapterState);
    484                 if (!isNormalStateTransition(prevState, state)) {
    485                     Log.w(TAG,
    486                             "ADAPTER_CONNECTION_STATE_CHANGE: unexpected transition for profile="
    487                                     + profile + ", device=" + device + ", " + prevState + " -> "
    488                                     + state);
    489                 }
    490                 mService.sendBroadcastAsUser(intent, UserHandle.ALL, AdapterService.BLUETOOTH_PERM);
    491             }
    492         }
    493     }
    494 
    495     private boolean validateProfileConnectionState(int state) {
    496         return (state == BluetoothProfile.STATE_DISCONNECTED ||
    497                 state == BluetoothProfile.STATE_CONNECTING ||
    498                 state == BluetoothProfile.STATE_CONNECTED ||
    499                 state == BluetoothProfile.STATE_DISCONNECTING);
    500     }
    501 
    502     private static int convertToAdapterState(int state) {
    503         switch (state) {
    504             case BluetoothProfile.STATE_DISCONNECTED:
    505                 return BluetoothAdapter.STATE_DISCONNECTED;
    506             case BluetoothProfile.STATE_DISCONNECTING:
    507                 return BluetoothAdapter.STATE_DISCONNECTING;
    508             case BluetoothProfile.STATE_CONNECTED:
    509                 return BluetoothAdapter.STATE_CONNECTED;
    510             case BluetoothProfile.STATE_CONNECTING:
    511                 return BluetoothAdapter.STATE_CONNECTING;
    512         }
    513         Log.e(TAG, "convertToAdapterState, unknow state " + state);
    514         return -1;
    515     }
    516 
    517     private static boolean isNormalStateTransition(int prevState, int nextState) {
    518         switch (prevState) {
    519             case BluetoothProfile.STATE_DISCONNECTED:
    520                 return nextState == BluetoothProfile.STATE_CONNECTING;
    521             case BluetoothProfile.STATE_CONNECTED:
    522                 return nextState == BluetoothProfile.STATE_DISCONNECTING;
    523             case BluetoothProfile.STATE_DISCONNECTING:
    524             case BluetoothProfile.STATE_CONNECTING:
    525                 return (nextState == BluetoothProfile.STATE_DISCONNECTED)
    526                         || (nextState == BluetoothProfile.STATE_CONNECTED);
    527             default:
    528                 return false;
    529         }
    530     }
    531 
    532     private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
    533         switch (prevState) {
    534             case BluetoothProfile.STATE_CONNECTING:
    535                 if (mProfilesConnecting > 0)
    536                     mProfilesConnecting--;
    537                 else
    538                     Log.e(TAG, "mProfilesConnecting " + mProfilesConnecting);
    539                 break;
    540 
    541             case BluetoothProfile.STATE_CONNECTED:
    542                 if (mProfilesConnected > 0)
    543                     mProfilesConnected--;
    544                 else
    545                     Log.e(TAG, "mProfilesConnected " + mProfilesConnected);
    546                 break;
    547 
    548             case BluetoothProfile.STATE_DISCONNECTING:
    549                 if (mProfilesDisconnecting > 0)
    550                     mProfilesDisconnecting--;
    551                 else
    552                     Log.e(TAG, "mProfilesDisconnecting " + mProfilesDisconnecting);
    553                 break;
    554         }
    555 
    556         switch (state) {
    557             case BluetoothProfile.STATE_CONNECTING:
    558                 mProfilesConnecting++;
    559                 return (mProfilesConnected == 0 && mProfilesConnecting == 1);
    560 
    561             case BluetoothProfile.STATE_CONNECTED:
    562                 mProfilesConnected++;
    563                 return (mProfilesConnected == 1);
    564 
    565             case BluetoothProfile.STATE_DISCONNECTING:
    566                 mProfilesDisconnecting++;
    567                 return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
    568 
    569             case BluetoothProfile.STATE_DISCONNECTED:
    570                 return (mProfilesConnected == 0 && mProfilesConnecting == 0);
    571 
    572             default:
    573                 return true;
    574         }
    575     }
    576 
    577     private void updateProfileConnectionState(int profile, int newState, int oldState) {
    578         // mProfileConnectionState is a hashmap -
    579         // <Integer, Pair<Integer, Integer>>
    580         // The key is the profile, the value is a pair. first element
    581         // is the state and the second element is the number of devices
    582         // in that state.
    583         int numDev = 1;
    584         int newHashState = newState;
    585         boolean update = true;
    586 
    587         // The following conditions are considered in this function:
    588         // 1. If there is no record of profile and state - update
    589         // 2. If a new device's state is current hash state - increment
    590         //    number of devices in the state.
    591         // 3. If a state change has happened to Connected or Connecting
    592         //    (if current state is not connected), update.
    593         // 4. If numDevices is 1 and that device state is being updated, update
    594         // 5. If numDevices is > 1 and one of the devices is changing state,
    595         //    decrement numDevices but maintain oldState if it is Connected or
    596         //    Connecting
    597         Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile);
    598         if (stateNumDev != null) {
    599             int currHashState = stateNumDev.first;
    600             numDev = stateNumDev.second;
    601 
    602             if (newState == currHashState) {
    603                 numDev ++;
    604             } else if (newState == BluetoothProfile.STATE_CONNECTED ||
    605                    (newState == BluetoothProfile.STATE_CONNECTING &&
    606                     currHashState != BluetoothProfile.STATE_CONNECTED)) {
    607                  numDev = 1;
    608             } else if (numDev == 1 && oldState == currHashState) {
    609                  update = true;
    610             } else if (numDev > 1 && oldState == currHashState) {
    611                  numDev --;
    612 
    613                  if (currHashState == BluetoothProfile.STATE_CONNECTED ||
    614                      currHashState == BluetoothProfile.STATE_CONNECTING) {
    615                     newHashState = currHashState;
    616                  }
    617             } else {
    618                  update = false;
    619             }
    620         }
    621 
    622         if (update) {
    623             mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState,
    624                     numDev));
    625         }
    626     }
    627 
    628     void adapterPropertyChangedCallback(int[] types, byte[][] values) {
    629         Intent intent;
    630         int type;
    631         byte[] val;
    632         for (int i = 0; i < types.length; i++) {
    633             val = values[i];
    634             type = types[i];
    635             infoLog("adapterPropertyChangedCallback with type:" + type + " len:" + val.length);
    636             synchronized (mObject) {
    637                 switch (type) {
    638                     case AbstractionLayer.BT_PROPERTY_BDNAME:
    639                         mName = new String(val);
    640                         intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
    641                         intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, mName);
    642                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    643                         mService.sendBroadcastAsUser(
    644                                 intent, UserHandle.ALL, AdapterService.BLUETOOTH_PERM);
    645                         debugLog("Name is: " + mName);
    646                         break;
    647                     case AbstractionLayer.BT_PROPERTY_BDADDR:
    648                         mAddress = val;
    649                         String address = Utils.getAddressStringFromByte(mAddress);
    650                         debugLog("Address is:" + address);
    651                         intent = new Intent(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
    652                         intent.putExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS, address);
    653                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    654                         mService.sendBroadcastAsUser(
    655                                 intent, UserHandle.ALL, AdapterService.BLUETOOTH_PERM);
    656                         break;
    657                     case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE:
    658                         mBluetoothClass = Utils.byteArrayToInt(val, 0);
    659                         debugLog("BT Class:" + mBluetoothClass);
    660                         break;
    661                     case AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE:
    662                         int mode = Utils.byteArrayToInt(val, 0);
    663                         mScanMode = AdapterService.convertScanModeFromHal(mode);
    664                         intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
    665                         intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mScanMode);
    666                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    667                         mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
    668                         debugLog("Scan Mode:" + mScanMode);
    669                         if (mBluetoothDisabling) {
    670                             mBluetoothDisabling=false;
    671                             mService.startBluetoothDisable();
    672                         }
    673                         break;
    674                     case AbstractionLayer.BT_PROPERTY_UUIDS:
    675                         mUuids = Utils.byteArrayToUuid(val);
    676                         break;
    677                     case AbstractionLayer.BT_PROPERTY_ADAPTER_BONDED_DEVICES:
    678                         int number = val.length/BD_ADDR_LEN;
    679                         byte[] addrByte = new byte[BD_ADDR_LEN];
    680                         for (int j = 0; j < number; j++) {
    681                             System.arraycopy(val, j * BD_ADDR_LEN, addrByte, 0, BD_ADDR_LEN);
    682                             onBondStateChanged(mAdapter.getRemoteDevice(
    683                                                Utils.getAddressStringFromByte(addrByte)),
    684                                                BluetoothDevice.BOND_BONDED);
    685                         }
    686                         break;
    687                     case AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT:
    688                         mDiscoverableTimeout = Utils.byteArrayToInt(val, 0);
    689                         debugLog("Discoverable Timeout:" + mDiscoverableTimeout);
    690                         break;
    691 
    692                     case AbstractionLayer.BT_PROPERTY_LOCAL_LE_FEATURES:
    693                         updateFeatureSupport(val);
    694                         break;
    695 
    696                     default:
    697                         errorLog("Property change not handled in Java land:" + type);
    698                 }
    699             }
    700         }
    701     }
    702 
    703     private void updateFeatureSupport(byte[] val) {
    704         mVersSupported = ((0xFF & ((int)val[1])) << 8)
    705                             + (0xFF & ((int)val[0]));
    706         mNumOfAdvertisementInstancesSupported = (0xFF & ((int)val[3]));
    707         mRpaOffloadSupported = ((0xFF & ((int)val[4]))!= 0);
    708         mNumOfOffloadedIrkSupported =  (0xFF & ((int)val[5]));
    709         mNumOfOffloadedScanFilterSupported = (0xFF & ((int)val[6]));
    710         mIsActivityAndEnergyReporting = ((0xFF & ((int)val[7])) != 0);
    711         mOffloadedScanResultStorageBytes = ((0xFF & ((int)val[9])) << 8)
    712                             + (0xFF & ((int)val[8]));
    713         mTotNumOfTrackableAdv = ((0xFF & ((int)val[11])) << 8)
    714                             + (0xFF & ((int)val[10]));
    715         mIsExtendedScanSupported = ((0xFF & ((int)val[12])) != 0);
    716         mIsDebugLogSupported = ((0xFF & ((int)val[13])) != 0);
    717         mIsLe2MPhySupported = ((0xFF & ((int) val[14])) != 0);
    718         mIsLeCodedPhySupported = ((0xFF & ((int) val[15])) != 0);
    719         mIsLeExtendedAdvertisingSupported = ((0xFF & ((int) val[16])) != 0);
    720         mIsLePeriodicAdvertisingSupported = ((0xFF & ((int) val[17])) != 0);
    721         mLeMaximumAdvertisingDataLength =   (0xFF & ((int)val[18]))
    722                                          + ((0xFF & ((int)val[19])) << 8);
    723 
    724         Log.d(TAG, "BT_PROPERTY_LOCAL_LE_FEATURES: update from BT controller"
    725                 + " mNumOfAdvertisementInstancesSupported = "
    726                 + mNumOfAdvertisementInstancesSupported
    727                 + " mRpaOffloadSupported = " + mRpaOffloadSupported
    728                 + " mNumOfOffloadedIrkSupported = "
    729                 + mNumOfOffloadedIrkSupported
    730                 + " mNumOfOffloadedScanFilterSupported = "
    731                 + mNumOfOffloadedScanFilterSupported
    732                 + " mOffloadedScanResultStorageBytes= "
    733                 + mOffloadedScanResultStorageBytes
    734                 + " mIsActivityAndEnergyReporting = "
    735                 + mIsActivityAndEnergyReporting
    736                 +" mVersSupported = "
    737                 + mVersSupported
    738                 + " mTotNumOfTrackableAdv = "
    739                 + mTotNumOfTrackableAdv
    740                 + " mIsExtendedScanSupported = "
    741                 + mIsExtendedScanSupported
    742                 + " mIsDebugLogSupported = "
    743                 + mIsDebugLogSupported
    744                 + " mIsLe2MPhySupported = "
    745                 + mIsLe2MPhySupported
    746                 + " mIsLeCodedPhySupported = "
    747                 + mIsLeCodedPhySupported
    748                 + " mIsLeExtendedAdvertisingSupported = "
    749                 + mIsLeExtendedAdvertisingSupported
    750                 + " mIsLePeriodicAdvertisingSupported = "
    751                 + mIsLePeriodicAdvertisingSupported
    752                 + " mLeMaximumAdvertisingDataLength = "
    753                 + mLeMaximumAdvertisingDataLength
    754                 );
    755     }
    756 
    757     void onBluetoothReady() {
    758         debugLog("onBluetoothReady, state=" + getState() + ", ScanMode=" + mScanMode);
    759 
    760         synchronized (mObject) {
    761             // Reset adapter and profile connection states
    762             setConnectionState(BluetoothAdapter.STATE_DISCONNECTED);
    763             mProfileConnectionState.clear();
    764             mProfilesConnected = 0;
    765             mProfilesConnecting = 0;
    766             mProfilesDisconnecting = 0;
    767             // When BT is being turned on, all adapter properties will be sent in 1
    768             // callback. At this stage, set the scan mode.
    769             if (getState() == BluetoothAdapter.STATE_TURNING_ON &&
    770                     mScanMode == BluetoothAdapter.SCAN_MODE_NONE) {
    771                     /* mDiscoverableTimeout is part of the
    772                        adapterPropertyChangedCallback received before
    773                        onBluetoothReady */
    774                     if (mDiscoverableTimeout != 0)
    775                       setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE);
    776                     else /* if timeout == never (0) at startup */
    777                       setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
    778                     /* though not always required, this keeps NV up-to date on first-boot after flash */
    779                     setDiscoverableTimeout(mDiscoverableTimeout);
    780             }
    781         }
    782     }
    783 
    784     private boolean mBluetoothDisabling = false;
    785 
    786     void onBleDisable() {
    787         // Sequence BLE_ON to STATE_OFF - that is _complete_ OFF state.
    788         // When BT disable is invoked, set the scan_mode to NONE
    789         // so no incoming connections are possible
    790         debugLog("onBleDisable");
    791         if (getState() == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
    792            setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE);
    793         }
    794     }
    795 
    796     void onBluetoothDisable() {
    797         // From STATE_ON to BLE_ON
    798         // When BT disable is invoked, set the scan_mode to NONE
    799         // so no incoming connections are possible
    800 
    801         //Set flag to indicate we are disabling. When property change of scan mode done
    802         //continue with disable sequence
    803         debugLog("onBluetoothDisable()");
    804         mBluetoothDisabling = true;
    805         if (getState() == BluetoothAdapter.STATE_TURNING_OFF) {
    806             // Turn off any Device Search/Inquiry
    807             mService.cancelDiscovery();
    808             setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE);
    809         }
    810     }
    811 
    812     void discoveryStateChangeCallback(int state) {
    813         infoLog("Callback:discoveryStateChangeCallback with state:" + state);
    814         synchronized (mObject) {
    815             Intent intent;
    816             if (state == AbstractionLayer.BT_DISCOVERY_STOPPED) {
    817                 mDiscovering = false;
    818                 mDiscoveryEndMs = System.currentTimeMillis();
    819                 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    820                 mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
    821             } else if (state == AbstractionLayer.BT_DISCOVERY_STARTED) {
    822                 mDiscovering = true;
    823                 mDiscoveryEndMs = System.currentTimeMillis() + DEFAULT_DISCOVERY_TIMEOUT_MS;
    824                 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
    825                 mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM);
    826             }
    827         }
    828     }
    829 
    830     private static void infoLog(String msg) {
    831         if (VDBG) Log.i(TAG, msg);
    832     }
    833 
    834     private static void debugLog(String msg) {
    835         if (DBG) Log.d(TAG, msg);
    836     }
    837 
    838     private static void errorLog(String msg) {
    839         Log.e(TAG, msg);
    840     }
    841 }
    842