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.BluetoothDevice;
     21 import android.bluetooth.BluetoothProfile;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.os.ParcelUuid;
     25 import android.os.UserHandle;
     26 import android.util.Log;
     27 import android.util.Pair;
     28 
     29 import com.android.bluetooth.Utils;
     30 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
     31 
     32 import java.util.HashMap;
     33 import java.util.ArrayList;
     34 import java.util.concurrent.CopyOnWriteArrayList;
     35 
     36 class AdapterProperties {
     37     private static final boolean DBG = true;
     38     private static final boolean VDBG = false;
     39     private static final String TAG = "BluetoothAdapterProperties";
     40 
     41     private static final int BD_ADDR_LEN = 6; // 6 bytes
     42     private volatile String mName;
     43     private volatile byte[] mAddress;
     44     private volatile int mBluetoothClass;
     45     private volatile int mScanMode;
     46     private volatile int mDiscoverableTimeout;
     47     private volatile ParcelUuid[] mUuids;
     48     private CopyOnWriteArrayList<BluetoothDevice> mBondedDevices = new CopyOnWriteArrayList<BluetoothDevice>();
     49 
     50     private int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting;
     51     private HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState;
     52 
     53 
     54     private volatile int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
     55     private volatile int mState = BluetoothAdapter.STATE_OFF;
     56 
     57     private AdapterService mService;
     58     private boolean mDiscovering;
     59     private RemoteDevices mRemoteDevices;
     60     private BluetoothAdapter mAdapter;
     61     //TODO - all hw capabilities to be exposed as a class
     62     private int mNumOfAdvertisementInstancesSupported;
     63     private boolean mRpaOffloadSupported;
     64     private int mNumOfOffloadedIrkSupported;
     65     private int mNumOfOffloadedScanFilterSupported;
     66     private int mOffloadedScanResultStorageBytes;
     67     private int mVersSupported;
     68     private int mTotNumOfTrackableAdv;
     69     private boolean mIsExtendedScanSupported;
     70     private boolean mIsDebugLogSupported;
     71     private boolean mIsActivityAndEnergyReporting;
     72 
     73     // Lock for all getters and setters.
     74     // If finer grained locking is needer, more locks
     75     // can be added here.
     76     private Object mObject = new Object();
     77 
     78     public AdapterProperties(AdapterService service) {
     79         mService = service;
     80         mAdapter = BluetoothAdapter.getDefaultAdapter();
     81     }
     82     public void init(RemoteDevices remoteDevices) {
     83         if (mProfileConnectionState ==null) {
     84             mProfileConnectionState = new HashMap<Integer, Pair<Integer, Integer>>();
     85         } else {
     86             mProfileConnectionState.clear();
     87         }
     88         mRemoteDevices = remoteDevices;
     89     }
     90 
     91     public void cleanup() {
     92         mRemoteDevices = null;
     93         if (mProfileConnectionState != null) {
     94             mProfileConnectionState.clear();
     95             mProfileConnectionState = null;
     96         }
     97         mService = null;
     98         mBondedDevices.clear();
     99     }
    100 
    101     @Override
    102     public Object clone() throws CloneNotSupportedException {
    103         throw new CloneNotSupportedException();
    104     }
    105 
    106     /**
    107      * @return the mName
    108      */
    109     String getName() {
    110         return mName;
    111     }
    112 
    113     /**
    114      * Set the local adapter property - name
    115      * @param name the name to set
    116      */
    117     boolean setName(String name) {
    118         synchronized (mObject) {
    119             return mService.setAdapterPropertyNative(
    120                     AbstractionLayer.BT_PROPERTY_BDNAME, name.getBytes());
    121         }
    122     }
    123 
    124     /**
    125      * @return the mClass
    126      */
    127     int getBluetoothClass() {
    128         return mBluetoothClass;
    129     }
    130 
    131     /**
    132      * @return the mScanMode
    133      */
    134     int getScanMode() {
    135         return mScanMode;
    136     }
    137 
    138     /**
    139      * Set the local adapter property - scanMode
    140      *
    141      * @param scanMode the ScanMode to set
    142      */
    143     boolean setScanMode(int scanMode) {
    144         synchronized (mObject) {
    145             return mService.setAdapterPropertyNative(
    146                     AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE, Utils.intToByteArray(scanMode));
    147         }
    148     }
    149 
    150     /**
    151      * @return the mUuids
    152      */
    153     ParcelUuid[] getUuids() {
    154         return mUuids;
    155     }
    156 
    157     /**
    158      * Set local adapter UUIDs.
    159      *
    160      * @param uuids the uuids to be set.
    161      */
    162     boolean setUuids(ParcelUuid[] uuids) {
    163         synchronized (mObject) {
    164             return mService.setAdapterPropertyNative(
    165                     AbstractionLayer.BT_PROPERTY_UUIDS, Utils.uuidsToByteArray(uuids));
    166         }
    167     }
    168 
    169     /**
    170      * @return the mAddress
    171      */
    172     byte[] getAddress() {
    173         return mAddress;
    174     }
    175 
    176     /**
    177      * @param mConnectionState the mConnectionState to set
    178      */
    179     void setConnectionState(int mConnectionState) {
    180         this.mConnectionState = mConnectionState;
    181     }
    182 
    183     /**
    184      * @return the mConnectionState
    185      */
    186     int getConnectionState() {
    187         return mConnectionState;
    188     }
    189 
    190     /**
    191      * @param mState the mState to set
    192      */
    193     void setState(int mState) {
    194         debugLog("Setting state to " + mState);
    195         this.mState = mState;
    196     }
    197 
    198     /**
    199      * @return the mState
    200      */
    201     int getState() {
    202         return mState;
    203     }
    204 
    205     /**
    206      * @return the mNumOfAdvertisementInstancesSupported
    207      */
    208     int getNumOfAdvertisementInstancesSupported() {
    209         return mNumOfAdvertisementInstancesSupported;
    210     }
    211 
    212     /**
    213      * @return the mRpaOffloadSupported
    214      */
    215     boolean isRpaOffloadSupported() {
    216         return mRpaOffloadSupported;
    217     }
    218 
    219     /**
    220      * @return the mNumOfOffloadedIrkSupported
    221      */
    222     int getNumOfOffloadedIrkSupported() {
    223         return mNumOfOffloadedIrkSupported;
    224     }
    225 
    226     /**
    227      * @return the mNumOfOffloadedScanFilterSupported
    228      */
    229     int getNumOfOffloadedScanFilterSupported() {
    230         return mNumOfOffloadedScanFilterSupported;
    231     }
    232 
    233     /**
    234      * @return the mOffloadedScanResultStorageBytes
    235      */
    236     int getOffloadedScanResultStorage() {
    237         return mOffloadedScanResultStorageBytes;
    238     }
    239 
    240     /**
    241      * @return tx/rx/idle activity and energy info
    242      */
    243     boolean isActivityAndEnergyReportingSupported() {
    244         return mIsActivityAndEnergyReporting;
    245     }
    246 
    247     /**
    248      * @return total number of trackable advertisements
    249      */
    250     int getTotalNumOfTrackableAdvertisements() {
    251         return mTotNumOfTrackableAdv;
    252     }
    253 
    254     /**
    255      * @return the mBondedDevices
    256      */
    257     BluetoothDevice[] getBondedDevices() {
    258         BluetoothDevice[] bondedDeviceList = new BluetoothDevice[0];
    259         try {
    260             bondedDeviceList = mBondedDevices.toArray(bondedDeviceList);
    261         } catch(ArrayStoreException ee) {
    262             errorLog("Error retrieving bonded device array");
    263         }
    264         infoLog("getBondedDevices: length=" + bondedDeviceList.length);
    265         return bondedDeviceList;
    266     }
    267 
    268     // This function shall be invoked from BondStateMachine whenever the bond
    269     // state changes.
    270     void onBondStateChanged(BluetoothDevice device, int state)
    271     {
    272         if(device == null)
    273             return;
    274         try {
    275             byte[] addrByte = Utils.getByteAddress(device);
    276             DeviceProperties prop = mRemoteDevices.getDeviceProperties(device);
    277             if (prop == null)
    278                 prop = mRemoteDevices.addDeviceProperties(addrByte);
    279             prop.setBondState(state);
    280 
    281             if (state == BluetoothDevice.BOND_BONDED) {
    282                 // add if not already in list
    283                 if(!mBondedDevices.contains(device)) {
    284                     debugLog("Adding bonded device:" +  device);
    285                     mBondedDevices.add(device);
    286                 }
    287             } else if (state == BluetoothDevice.BOND_NONE) {
    288                 // remove device from list
    289                 if (mBondedDevices.remove(device))
    290                     debugLog("Removing bonded device:" +  device);
    291                 else
    292                     debugLog("Failed to remove device: " + device);
    293             }
    294         }
    295         catch(Exception ee) {
    296             Log.e(TAG, "Exception in onBondStateChanged : ", ee);
    297         }
    298     }
    299 
    300     int getDiscoverableTimeout() {
    301         return mDiscoverableTimeout;
    302     }
    303 
    304     boolean setDiscoverableTimeout(int timeout) {
    305         synchronized (mObject) {
    306             return mService.setAdapterPropertyNative(
    307                     AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT,
    308                     Utils.intToByteArray(timeout));
    309         }
    310     }
    311 
    312     int getProfileConnectionState(int profile) {
    313         synchronized (mObject) {
    314             Pair<Integer, Integer> p = mProfileConnectionState.get(profile);
    315             if (p != null) return p.first;
    316             return BluetoothProfile.STATE_DISCONNECTED;
    317         }
    318     }
    319 
    320     boolean isDiscovering() {
    321         return mDiscovering;
    322     }
    323 
    324     void sendConnectionStateChange(BluetoothDevice device, int profile, int state, int prevState) {
    325         if (!validateProfileConnectionState(state) ||
    326                 !validateProfileConnectionState(prevState)) {
    327             // Previously, an invalid state was broadcast anyway,
    328             // with the invalid state converted to -1 in the intent.
    329             // Better to log an error and not send an intent with
    330             // invalid contents or set mAdapterConnectionState to -1.
    331             errorLog("Error in sendConnectionStateChange: "
    332                     + "prevState " + prevState + " state " + state);
    333             return;
    334         }
    335 
    336         synchronized (mObject) {
    337             updateProfileConnectionState(profile, state, prevState);
    338 
    339             if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
    340                 setConnectionState(state);
    341 
    342                 Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
    343                 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
    344                 intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
    345                         convertToAdapterState(state));
    346                 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE,
    347                         convertToAdapterState(prevState));
    348                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    349                 mService.sendBroadcastAsUser(intent, UserHandle.ALL,
    350                         mService.BLUETOOTH_PERM);
    351                 Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": "
    352                         + prevState + " -> " + state);
    353             }
    354         }
    355     }
    356 
    357     private boolean validateProfileConnectionState(int state) {
    358         return (state == BluetoothProfile.STATE_DISCONNECTED ||
    359                 state == BluetoothProfile.STATE_CONNECTING ||
    360                 state == BluetoothProfile.STATE_CONNECTED ||
    361                 state == BluetoothProfile.STATE_DISCONNECTING);
    362     }
    363 
    364 
    365     private int convertToAdapterState(int state) {
    366         switch (state) {
    367             case BluetoothProfile.STATE_DISCONNECTED:
    368                 return BluetoothAdapter.STATE_DISCONNECTED;
    369             case BluetoothProfile.STATE_DISCONNECTING:
    370                 return BluetoothAdapter.STATE_DISCONNECTING;
    371             case BluetoothProfile.STATE_CONNECTED:
    372                 return BluetoothAdapter.STATE_CONNECTED;
    373             case BluetoothProfile.STATE_CONNECTING:
    374                 return BluetoothAdapter.STATE_CONNECTING;
    375         }
    376         Log.e(TAG, "Error in convertToAdapterState");
    377         return -1;
    378     }
    379 
    380     private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
    381         switch (prevState) {
    382             case BluetoothProfile.STATE_CONNECTING:
    383                 mProfilesConnecting--;
    384                 break;
    385 
    386             case BluetoothProfile.STATE_CONNECTED:
    387                 mProfilesConnected--;
    388                 break;
    389 
    390             case BluetoothProfile.STATE_DISCONNECTING:
    391                 mProfilesDisconnecting--;
    392                 break;
    393         }
    394 
    395         switch (state) {
    396             case BluetoothProfile.STATE_CONNECTING:
    397                 mProfilesConnecting++;
    398                 return (mProfilesConnected == 0 && mProfilesConnecting == 1);
    399 
    400             case BluetoothProfile.STATE_CONNECTED:
    401                 mProfilesConnected++;
    402                 return (mProfilesConnected == 1);
    403 
    404             case BluetoothProfile.STATE_DISCONNECTING:
    405                 mProfilesDisconnecting++;
    406                 return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
    407 
    408             case BluetoothProfile.STATE_DISCONNECTED:
    409                 return (mProfilesConnected == 0 && mProfilesConnecting == 0);
    410 
    411             default:
    412                 return true;
    413         }
    414     }
    415 
    416     private void updateProfileConnectionState(int profile, int newState, int oldState) {
    417         // mProfileConnectionState is a hashmap -
    418         // <Integer, Pair<Integer, Integer>>
    419         // The key is the profile, the value is a pair. first element
    420         // is the state and the second element is the number of devices
    421         // in that state.
    422         int numDev = 1;
    423         int newHashState = newState;
    424         boolean update = true;
    425 
    426         // The following conditions are considered in this function:
    427         // 1. If there is no record of profile and state - update
    428         // 2. If a new device's state is current hash state - increment
    429         //    number of devices in the state.
    430         // 3. If a state change has happened to Connected or Connecting
    431         //    (if current state is not connected), update.
    432         // 4. If numDevices is 1 and that device state is being updated, update
    433         // 5. If numDevices is > 1 and one of the devices is changing state,
    434         //    decrement numDevices but maintain oldState if it is Connected or
    435         //    Connecting
    436         Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile);
    437         if (stateNumDev != null) {
    438             int currHashState = stateNumDev.first;
    439             numDev = stateNumDev.second;
    440 
    441             if (newState == currHashState) {
    442                 numDev ++;
    443             } else if (newState == BluetoothProfile.STATE_CONNECTED ||
    444                    (newState == BluetoothProfile.STATE_CONNECTING &&
    445                     currHashState != BluetoothProfile.STATE_CONNECTED)) {
    446                  numDev = 1;
    447             } else if (numDev == 1 && oldState == currHashState) {
    448                  update = true;
    449             } else if (numDev > 1 && oldState == currHashState) {
    450                  numDev --;
    451 
    452                  if (currHashState == BluetoothProfile.STATE_CONNECTED ||
    453                      currHashState == BluetoothProfile.STATE_CONNECTING) {
    454                     newHashState = currHashState;
    455                  }
    456             } else {
    457                  update = false;
    458             }
    459         }
    460 
    461         if (update) {
    462             mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState,
    463                     numDev));
    464         }
    465     }
    466 
    467     void adapterPropertyChangedCallback(int[] types, byte[][] values) {
    468         Intent intent;
    469         int type;
    470         byte[] val;
    471         for (int i = 0; i < types.length; i++) {
    472             val = values[i];
    473             type = types[i];
    474             infoLog("adapterPropertyChangedCallback with type:" + type + " len:" + val.length);
    475             synchronized (mObject) {
    476                 switch (type) {
    477                     case AbstractionLayer.BT_PROPERTY_BDNAME:
    478                         mName = new String(val);
    479                         intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
    480                         intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, mName);
    481                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    482                         mService.sendBroadcastAsUser(intent, UserHandle.ALL,
    483                                  mService.BLUETOOTH_PERM);
    484                         debugLog("Name is: " + mName);
    485                         break;
    486                     case AbstractionLayer.BT_PROPERTY_BDADDR:
    487                         mAddress = val;
    488                         debugLog("Address is:" + Utils.getAddressStringFromByte(mAddress));
    489                         break;
    490                     case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE:
    491                         mBluetoothClass = Utils.byteArrayToInt(val, 0);
    492                         debugLog("BT Class:" + mBluetoothClass);
    493                         break;
    494                     case AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE:
    495                         int mode = Utils.byteArrayToInt(val, 0);
    496                         mScanMode = mService.convertScanModeFromHal(mode);
    497                         intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
    498                         intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mScanMode);
    499                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    500                         mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
    501                         debugLog("Scan Mode:" + mScanMode);
    502                         if (mBluetoothDisabling) {
    503                             mBluetoothDisabling=false;
    504                             mService.startBluetoothDisable();
    505                         }
    506                         break;
    507                     case AbstractionLayer.BT_PROPERTY_UUIDS:
    508                         mUuids = Utils.byteArrayToUuid(val);
    509                         break;
    510                     case AbstractionLayer.BT_PROPERTY_ADAPTER_BONDED_DEVICES:
    511                         int number = val.length/BD_ADDR_LEN;
    512                         byte[] addrByte = new byte[BD_ADDR_LEN];
    513                         for (int j = 0; j < number; j++) {
    514                             System.arraycopy(val, j * BD_ADDR_LEN, addrByte, 0, BD_ADDR_LEN);
    515                             onBondStateChanged(mAdapter.getRemoteDevice(
    516                                                Utils.getAddressStringFromByte(addrByte)),
    517                                                BluetoothDevice.BOND_BONDED);
    518                         }
    519                         break;
    520                     case AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT:
    521                         mDiscoverableTimeout = Utils.byteArrayToInt(val, 0);
    522                         debugLog("Discoverable Timeout:" + mDiscoverableTimeout);
    523                         break;
    524 
    525                     case AbstractionLayer.BT_PROPERTY_LOCAL_LE_FEATURES:
    526                         updateFeatureSupport(val);
    527                         break;
    528 
    529                     default:
    530                         errorLog("Property change not handled in Java land:" + type);
    531                 }
    532             }
    533         }
    534     }
    535 
    536     void updateFeatureSupport(byte[] val) {
    537         mVersSupported = ((0xFF & ((int)val[1])) << 8)
    538                             + (0xFF & ((int)val[0]));
    539         mNumOfAdvertisementInstancesSupported = (0xFF & ((int)val[3]));
    540         mRpaOffloadSupported = ((0xFF & ((int)val[4]))!= 0);
    541         mNumOfOffloadedIrkSupported =  (0xFF & ((int)val[5]));
    542         mNumOfOffloadedScanFilterSupported = (0xFF & ((int)val[6]));
    543         mIsActivityAndEnergyReporting = ((0xFF & ((int)val[7])) != 0);
    544         mOffloadedScanResultStorageBytes = ((0xFF & ((int)val[9])) << 8)
    545                             + (0xFF & ((int)val[8]));
    546         mTotNumOfTrackableAdv = ((0xFF & ((int)val[11])) << 8)
    547                             + (0xFF & ((int)val[10]));
    548         mIsExtendedScanSupported = ((0xFF & ((int)val[12])) != 0);
    549         mIsDebugLogSupported = ((0xFF & ((int)val[13])) != 0);
    550 
    551         Log.d(TAG, "BT_PROPERTY_LOCAL_LE_FEATURES: update from BT controller"
    552                 + " mNumOfAdvertisementInstancesSupported = "
    553                 + mNumOfAdvertisementInstancesSupported
    554                 + " mRpaOffloadSupported = " + mRpaOffloadSupported
    555                 + " mNumOfOffloadedIrkSupported = "
    556                 + mNumOfOffloadedIrkSupported
    557                 + " mNumOfOffloadedScanFilterSupported = "
    558                 + mNumOfOffloadedScanFilterSupported
    559                 + " mOffloadedScanResultStorageBytes= "
    560                 + mOffloadedScanResultStorageBytes
    561                 + " mIsActivityAndEnergyReporting = "
    562                 + mIsActivityAndEnergyReporting
    563                 +" mVersSupported = "
    564                 + mVersSupported
    565                 + " mTotNumOfTrackableAdv = "
    566                 + mTotNumOfTrackableAdv
    567                 + " mIsExtendedScanSupported = "
    568                 + mIsExtendedScanSupported
    569                 + " mIsDebugLogSupported = "
    570                 + mIsDebugLogSupported
    571                 );
    572     }
    573 
    574     void onBluetoothReady() {
    575         Log.d(TAG, "ScanMode =  " + mScanMode );
    576         Log.d(TAG, "State =  " + getState() );
    577 
    578         // When BT is being turned on, all adapter properties will be sent in 1
    579         // callback. At this stage, set the scan mode.
    580         synchronized (mObject) {
    581             if (getState() == BluetoothAdapter.STATE_TURNING_ON &&
    582                     mScanMode == BluetoothAdapter.SCAN_MODE_NONE) {
    583                     /* mDiscoverableTimeout is part of the
    584                        adapterPropertyChangedCallback received before
    585                        onBluetoothReady */
    586                     if (mDiscoverableTimeout != 0)
    587                       setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE);
    588                     else /* if timeout == never (0) at startup */
    589                       setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
    590                     /* though not always required, this keeps NV up-to date on first-boot after flash */
    591                     setDiscoverableTimeout(mDiscoverableTimeout);
    592             }
    593         }
    594     }
    595 
    596     private boolean mBluetoothDisabling = false;
    597 
    598     void onBleDisable() {
    599         // Sequence BLE_ON to STATE_OFF - that is _complete_ OFF state.
    600         // When BT disable is invoked, set the scan_mode to NONE
    601         // so no incoming connections are possible
    602         debugLog("onBleDisable");
    603         if (getState() == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
    604            setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE);
    605         }
    606     }
    607 
    608     void onBluetoothDisable() {
    609         // From STATE_ON to BLE_ON
    610         // When BT disable is invoked, set the scan_mode to NONE
    611         // so no incoming connections are possible
    612 
    613         //Set flag to indicate we are disabling. When property change of scan mode done
    614         //continue with disable sequence
    615         debugLog("onBluetoothDisable()");
    616         mBluetoothDisabling = true;
    617         if (getState() == BluetoothAdapter.STATE_TURNING_OFF) {
    618             // Turn off any Device Search/Inquiry
    619             mService.cancelDiscovery();
    620             setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE);
    621         }
    622     }
    623 
    624     void discoveryStateChangeCallback(int state) {
    625         infoLog("Callback:discoveryStateChangeCallback with state:" + state);
    626         synchronized (mObject) {
    627             Intent intent;
    628             if (state == AbstractionLayer.BT_DISCOVERY_STOPPED) {
    629                 mDiscovering = false;
    630                 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    631                 mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
    632             } else if (state == AbstractionLayer.BT_DISCOVERY_STARTED) {
    633                 mDiscovering = true;
    634                 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
    635                 mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
    636             }
    637         }
    638     }
    639 
    640     private void infoLog(String msg) {
    641         if (VDBG) Log.i(TAG, msg);
    642     }
    643 
    644     private void debugLog(String msg) {
    645         if (DBG) Log.d(TAG, msg);
    646     }
    647 
    648     private void errorLog(String msg) {
    649         Log.e(TAG, msg);
    650     }
    651 }
    652