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 
AdapterProperties(AdapterService service)78     public AdapterProperties(AdapterService service) {
79         mService = service;
80         mAdapter = BluetoothAdapter.getDefaultAdapter();
81     }
init(RemoteDevices remoteDevices)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 
cleanup()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
clone()102     public Object clone() throws CloneNotSupportedException {
103         throw new CloneNotSupportedException();
104     }
105 
106     /**
107      * @return the mName
108      */
getName()109     String getName() {
110         return mName;
111     }
112 
113     /**
114      * Set the local adapter property - name
115      * @param name the name to set
116      */
setName(String name)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      */
getBluetoothClass()127     int getBluetoothClass() {
128         return mBluetoothClass;
129     }
130 
131     /**
132      * @return the mScanMode
133      */
getScanMode()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      */
setScanMode(int scanMode)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      */
getUuids()153     ParcelUuid[] getUuids() {
154         return mUuids;
155     }
156 
157     /**
158      * Set local adapter UUIDs.
159      *
160      * @param uuids the uuids to be set.
161      */
setUuids(ParcelUuid[] uuids)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      */
getAddress()172     byte[] getAddress() {
173         return mAddress;
174     }
175 
176     /**
177      * @param mConnectionState the mConnectionState to set
178      */
setConnectionState(int mConnectionState)179     void setConnectionState(int mConnectionState) {
180         this.mConnectionState = mConnectionState;
181     }
182 
183     /**
184      * @return the mConnectionState
185      */
getConnectionState()186     int getConnectionState() {
187         return mConnectionState;
188     }
189 
190     /**
191      * @param mState the mState to set
192      */
setState(int mState)193     void setState(int mState) {
194         debugLog("Setting state to " + mState);
195         this.mState = mState;
196     }
197 
198     /**
199      * @return the mState
200      */
getState()201     int getState() {
202         return mState;
203     }
204 
205     /**
206      * @return the mNumOfAdvertisementInstancesSupported
207      */
getNumOfAdvertisementInstancesSupported()208     int getNumOfAdvertisementInstancesSupported() {
209         return mNumOfAdvertisementInstancesSupported;
210     }
211 
212     /**
213      * @return the mRpaOffloadSupported
214      */
isRpaOffloadSupported()215     boolean isRpaOffloadSupported() {
216         return mRpaOffloadSupported;
217     }
218 
219     /**
220      * @return the mNumOfOffloadedIrkSupported
221      */
getNumOfOffloadedIrkSupported()222     int getNumOfOffloadedIrkSupported() {
223         return mNumOfOffloadedIrkSupported;
224     }
225 
226     /**
227      * @return the mNumOfOffloadedScanFilterSupported
228      */
getNumOfOffloadedScanFilterSupported()229     int getNumOfOffloadedScanFilterSupported() {
230         return mNumOfOffloadedScanFilterSupported;
231     }
232 
233     /**
234      * @return the mOffloadedScanResultStorageBytes
235      */
getOffloadedScanResultStorage()236     int getOffloadedScanResultStorage() {
237         return mOffloadedScanResultStorageBytes;
238     }
239 
240     /**
241      * @return tx/rx/idle activity and energy info
242      */
isActivityAndEnergyReportingSupported()243     boolean isActivityAndEnergyReportingSupported() {
244         return mIsActivityAndEnergyReporting;
245     }
246 
247     /**
248      * @return total number of trackable advertisements
249      */
getTotalNumOfTrackableAdvertisements()250     int getTotalNumOfTrackableAdvertisements() {
251         return mTotNumOfTrackableAdv;
252     }
253 
254     /**
255      * @return the mBondedDevices
256      */
getBondedDevices()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.
onBondStateChanged(BluetoothDevice device, int state)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 
getDiscoverableTimeout()300     int getDiscoverableTimeout() {
301         return mDiscoverableTimeout;
302     }
303 
setDiscoverableTimeout(int timeout)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 
getProfileConnectionState(int profile)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 
isDiscovering()320     boolean isDiscovering() {
321         return mDiscovering;
322     }
323 
sendConnectionStateChange(BluetoothDevice device, int profile, int state, int prevState)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 
validateProfileConnectionState(int state)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 
convertToAdapterState(int state)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 
updateCountersAndCheckForConnectionStateChange(int state, int prevState)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 
updateProfileConnectionState(int profile, int newState, int oldState)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 
adapterPropertyChangedCallback(int[] types, byte[][] values)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 
updateFeatureSupport(byte[] val)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 
onBluetoothReady()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 
onBleDisable()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 
onBluetoothDisable()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 
discoveryStateChangeCallback(int state)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 
infoLog(String msg)640     private void infoLog(String msg) {
641         if (VDBG) Log.i(TAG, msg);
642     }
643 
debugLog(String msg)644     private void debugLog(String msg) {
645         if (DBG) Log.d(TAG, msg);
646     }
647 
errorLog(String msg)648     private void errorLog(String msg) {
649         Log.e(TAG, msg);
650     }
651 }
652