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