频道栏目
首页 > 资讯 > Android > 正文

Android 如何获取已连接的蓝牙地址

17-03-11        来源:[db:作者]  
收藏   我要投稿

Android 如何获取已连接的蓝牙地址,项目中有一个需求,就是获取已连接的蓝牙地址。

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 mDevices = proxy.getConnectedDevices();
                if (mDevices != null && mDevices.size() > 0) {
                    for (BluetoothDevice device : mDevices) {
                        Log.d(TAG,device.getName() + "," + device.getAddress());
                    }
                } else {

                }
            }
        }, flag);

        }
    }

从网上看到这段代码并没有作用,由于flag一直等于-1,所以一直返回BluetoothProfile.STATE_DISCONNECTED。也就是说
        int a2dp = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);
        int headset = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
        int health = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEALTH);
这三个方法都是返回的BluetoothProfile.STATE_DISCONNECTED
    /**
     * 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}.
     *
     * 

Requires {@link android.Manifest.permission#BLUETOOTH}. * *

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是IBluetooth接口对象
    /**
     * 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();
        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;
    }

我们看到managerService是IBluetoothManager的Proxy,我们来找找Stub端在哪。
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;
        }
    }

我们继续看BluetoothAdapter的mService到底是什么
mBluetooth = IBluetooth.Stub.asInterface(service);
private static class AdapterServiceBinder extends IBluetooth.Stub

原来BluetoothAdapter的mService = mBluetooth = IBluetooth.Stub.asInterface(service),BluetoothManagerService只是个门面而已,真正干活的是IBluetooth.Stub也就是AdapterServiceBinder。我们回到最开始的问题,我们看AdapterService的getProfileConnectionState方法

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

        return mAdapterProperties.getProfileConnectionState(profile);
    }
我们继续看AdapterProperties类
    int getProfileConnectionState(int profile) {
        synchronized (mObject) {
            Pair p = mProfileConnectionState.get(profile);
            if (p != null) return p.first;
            return BluetoothProfile.STATE_DISCONNECTED;
        }
    }

mProfileConnectionState是干什么用的,在此之前我们先看看蓝牙的一些基本概念。

BluetoothProfile
描述Bluetooth Profile的接口。Bluetooth Profile是两个设备基于蓝牙通讯的无线接口描述。
(对Bluetooth Profile的详细解释,来自百度:为了更容易的保持Bluetooth设备之间的兼容,Bluetooth规范中定义了 Profile。Profile定义了设备如何实现一种连接或者应用,你可以把Profile理解为连接层或者应用层协议。 比如,如果一家公司希望它们的Bluetooth芯片支援所有的Bluetooth耳机,那么它只要支持HeadSet Profile即可,而无须考虑该芯片与其它Bluetooth设备的通讯与兼容性问题。如果你想购买Bluetooth产品,你应该了解你的应用需要哪 些Profile来完成,并且确保你购买的Bluetooth产品支持这些Profile。)
BluetoothHeadset
提供移动电话的Bluetooth耳机支持。包括Bluetooth耳机和Hands-Free (v1.5) profiles。
BluetoothA2dp
定义两个设备间如何通过Bluetooth连接进行高质量的音频传输。
A2DP(Advanced Audio Distribution Profile):高级音频传输模式。

mProfileConnectionState也就是管理各种profile连接情况的一个集合

很显然,我们最开始那段代码不起作用,是因为profile不对,我们来看profile都有哪些

/**
     * 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;

我们列举了主要的几种,除了我们测试的HEADSET、A2DP、HEALTH外,还有GATT和GATT_SERVER,其实都是Hide。最开始的代码加上GATT和GATT_SERVER之后,依然没有结果。

实在没有办法了,我看到了BluetoothAdapter有一个hide方法直接调用了AdapterProperties的getConnectionState方法。

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

 Class bluetoothAdapterClass = BluetoothAdapter.class;//得到TelephonyManager的Class对象
        try {//得到挂断电话的方法
            Method method = bluetoothAdapterClass.getDeclaredMethod("getConnectionState", (Class[]) null);
            //打开权限
            method.setAccessible(true);
            int state = (int) method.invoke(_bluetoothAdapter, (Object[]) null);

            if(state == BluetoothAdapter.STATE_CONNECTED){

                LogUtil.i("BluetoothAdapter.STATE_CONNECTED");

                Set 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();
        }

利用反射获取了当前蓝牙连接的状态,根据getBondedDevices获取已绑定的蓝牙连接,然后遍历BluetoothDevice,同样利用反射的方法调用BluetoothDevice的isConnected方法。成功获取。
相关TAG标签
上一篇:java设计模式(三)策略模式(行为型)
下一篇:机器学习(四)从信息论交叉熵的角度看softmax/逻辑回归损失
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站