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