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