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