How Android Gets Connected Bluetooth Address

Keywords: Android Mobile

One requirement of the project is to get the Bluetooth address that has been connected.

private void getConnectBt() {
        LogUtil.i("getConnectBt");

        int a2dp = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);
        int headset = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
        int health = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEALTH);
        int flag = -1;
        if (a2dp == BluetoothProfile.STATE_CONNECTED) {
            flag = a2dp;
        } else if (headset == BluetoothProfile.STATE_CONNECTED) {
            flag = headset;
        } else if (health == BluetoothProfile.STATE_CONNECTED) {
            flag = health;
        }

        Log.d(TAG,"flag:"+flag);
        if (flag != -1) {
        _bluetoothAdapter.getProfileProxy(_context, new BluetoothProfile.ServiceListener() {
            @Override
            public void onServiceDisconnected(int profile) {

            }

            @Override
            public void onServiceConnected(int profile, BluetoothProfile proxy) {
                List<BluetoothDevice> mDevices = proxy.getConnectedDevices();
                if (mDevices != null && mDevices.size() > 0) {
                    for (BluetoothDevice device : mDevices) {
                        Log.d(TAG,device.getName() + "," + device.getAddress());
                    }
                } else {

                }
            }
        }, flag);

        }
    }

Seen from the internet, this code does not work because flag has always been equal to - 1, so it has been returned to Bluetooth Profile. STATE_DISCONNECTED. In other words
        int a2dp = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);
        int headset = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
        int health = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEALTH);
All three methods are Bluetooth Profile. STATE_DISCONNECTED returned

    /**
     * Get the current connection state of a profile.
     * This function can be used to check whether the local Bluetooth adapter
     * is connected to any remote device for a specific profile.
     * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
     * {@link BluetoothProfile#A2DP}.
     *
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
     *
     * <p> Return value can be one of
     * {@link BluetoothProfile#STATE_DISCONNECTED},
     * {@link BluetoothProfile#STATE_CONNECTING},
     * {@link BluetoothProfile#STATE_CONNECTED},
     * {@link BluetoothProfile#STATE_DISCONNECTING}
     */
    public int getProfileConnectionState(int profile) {
        if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
        try {
            synchronized(mManagerCallback) {
                if (mService != null) return mService.getProfileConnectionState(profile);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "getProfileConnectionState:", e);
        }
        return BluetoothProfile.STATE_DISCONNECTED;
    }

mService is an IBluetooth interface object

    /**
     * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
     */
    BluetoothAdapter(IBluetoothManager managerService) {

        if (managerService == null) {
            throw new IllegalArgumentException("bluetooth manager service is null");
        }
        try {
            mService = managerService.registerAdapter(mManagerCallback);
        } catch (RemoteException e) {Log.e(TAG, "", e);}
        mManagerService = managerService;
        mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
        mHandler = new Handler(Looper.getMainLooper());
    }

    public static synchronized BluetoothAdapter getDefaultAdapter() {
        if (sAdapter == null) {
            IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
            if (b != null) {
                IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
                sAdapter = new BluetoothAdapter(managerService);
            } else {
                Log.e(TAG, "Bluetooth binder is null");
            }
        }
        return sAdapter;
    }

We see that the manager service is the Proxy of IBluetooth Manager. Let's find out where the Stub end is.
private static class AdapterServiceBinder extends IBluetooth.Stub

class BluetoothManagerService extends IBluetoothManager.Stub

    public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
        msg.obj = callback;
        mHandler.sendMessage(msg);
        synchronized(mConnection) {
            return mBluetooth;
        }
    }

Let's continue to see what Bluetooth Adapter's mService is.

mBluetooth = IBluetooth.Stub.asInterface(service);
private static class AdapterServiceBinder extends IBluetooth.Stub

The original Bluetooth Adapter's mService = mBluetooth = IBluetooth.Stub.asInterface(service), Bluetooth Manager Service is just a facade, the real work is IBluetooth.Stub is also the Adapter Service Binder. Let's go back to the original question, let's look at the getProfileConnectionState method of AdapterService

     int getProfileConnectionState(int profile) {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");

        return mAdapterProperties.getProfileConnectionState(profile);
    }
Let's continue with the AdapterProperties class

    int getProfileConnectionState(int profile) {
        synchronized (mObject) {
            Pair<Integer, Integer> p = mProfileConnectionState.get(profile);
            if (p != null) return p.first;
            return BluetoothProfile.STATE_DISCONNECTED;
        }
    }

What does mProfile Connection State do? Before that, let's look at some basic concepts of Bluetooth.

BluetoothProfile
Describes the interface of Bluetooth Profile. Bluetooth Profile is a description of the wireless interface between two devices based on Bluetooth communication.
(Detailed explanation of Bluetooth Profile, from Baidu: To make it easier to maintain compatibility between Bluetooth devices, the Bluetooth specification defines Profile. Profile defines how a device implements a connection or application. You can understand Profile as a connection layer or application layer protocol. For example, if a company wants its Bluetooth chip to support all Bluetooth headphones, it can only support HeadSet Profile without considering the communication and compatibility between the chip and other Bluetooth devices. If you want to buy Bluetooth products, you should know what your application needs. Some Profiles to complete, and make sure that the Bluetooth products you buy support these Profiles.)
BluetoothHeadset
Bluetooth headset support for mobile phones. Includes Bluetooth headphones and Hands-Free (v1.5) profiles.
BluetoothA2dp
Define how to transmit high quality audio between two devices via Bluetooth connection.
A2DP (Advanced Audio Distribution Profile): Advanced Audio Transmission Mode.

MProfile Connection State is a collection that manages various profile connections

Obviously, the first piece of code didn't work because profiles weren't right. Let's see what profiles have.

/**
     * Headset and Handsfree profile
     */
    public static final int HEADSET = 1;

    /**
     * A2DP profile.
     */
    public static final int A2DP = 2;

    /**
     * Health Profile
     */
    public static final int HEALTH = 3;

    /**
     * Input Device Profile
     * @hide
     */
    public static final int INPUT_DEVICE = 4;

    /**
     * PAN Profile
     * @hide
     */
    public static final int PAN = 5;

    /**
     * PBAP
     * @hide
     */
    public static final int PBAP = 6;

    /**
     * GATT
     */
    static public final int GATT = 7;

    /**
     * GATT_SERVER
     */
    static public final int GATT_SERVER = 8;

We enumerate the main kinds, besides HEADSET, A2DP, HEALTH, GATT and GATT_SERVER, which are actually Hide. After adding GATT and GATT_SERVER to the original code, there is still no result.

There's nothing I can do about it. I saw that Bluetooth Adapter has a hide method that directly calls the getConnectionState method of Adapter Properties.

    /**
     * @return the mConnectionState
     */
    int getConnectionState() {
        synchronized (mObject) {
            return mConnectionState;
        }
    }

 Class<BluetoothAdapter> bluetoothAdapterClass = BluetoothAdapter.class;//Get the Class es object of TelephonyManager
        try {//How to get the hang-up call
            Method method = bluetoothAdapterClass.getDeclaredMethod("getConnectionState", (Class[]) null);
            //Open permission
            method.setAccessible(true);
            int state = (int) method.invoke(_bluetoothAdapter, (Object[]) null);

            if(state == BluetoothAdapter.STATE_CONNECTED){

                LogUtil.i("BluetoothAdapter.STATE_CONNECTED");

                Set<BluetoothDevice> devices = _bluetoothAdapter.getBondedDevices();
                LogUtil.i("devices:"+devices.size());

                for(BluetoothDevice device : devices){

                    Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected", (Class[]) null);
                    method.setAccessible(true);
                    boolean isConnected = (boolean) isConnectedMethod.invoke(device, (Object[]) null);

                    if(isConnected){
                        LogUtil.i("connected:"+device.getAddress());
                        return device.getAddress();
                    }

                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

The status of Bluetooth connection is acquired by reflection, the bound Bluetooth connection is acquired by getBondedDevices, and then Bluetooth Device is traversed. The isConnected method of Bluetooth Device is also invoked by reflection. Successful acquisition.


Reference article:

http://blog.csdn.net/mapeifan/article/details/50683956

Posted by thegame261 on Mon, 15 Apr 2019 11:30:31 -0700