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