日期:2014-05-20  浏览次数:20788 次

J2ME 蓝牙搜索与连接
import java.io.IOException;
import java.util.Vector;

import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DataElement;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.UUID;
import javax.microedition.io.Connection;
import javax.microedition.io.Connector;

/**
 * 蓝牙设备搜索及服务搜索类<BR>
 * 
 * 
 * @author Administrator
 * @version V1.0
 */
public final class BlueTooth implements DiscoveryListener , Runnable
{

    /**
     * 准备
     */
    public static final int STATUS_READY = 0x01;
    /**
     * 设备搜索中
     */
    public static final int STATUS_DEV_SEARCHING = 0x02;
    /**
     * 设备搜索完成
     */
    public static final int STATUS_DEV_SEARCH_FINISH = 0x03;
    /**
     * 设备搜索失败
     */
    public static final int STATUS_DEV_SEARCH_ERROR = 0x04;
    /**
     * 服务搜索中
     */
    public static final int STATUS_SER_SEARCHING = 0x10;
    /**
     * 服务搜索完成
     */
    public static final int STATUS_SER_SEARCH_FINISH = 0x11;
    /**
     * 服务搜索失败
     */
    public static final int STATUS_SER_SEARCH_ERROR = 0x12;
    /**
     * 创建与服务的连接中
     */
    public static final int STATUS_CONNECTING = 0x20;
    /**
     * 创建服务连接成功
     */
    public static final int STATUS_CONNECT_OK = 0x21;
    /**
     * 创建服务连接失败
     */
    public static final int STATUS_CONNECT_FAIL = 0x22;
    /**
     * 单实例
     */
    private static BlueTooth instance = new BlueTooth();

    /**
     * 本地设备
     */
    protected LocalDevice localDevice;
    /**
     * 设备搜索代理
     */
    protected DiscoveryAgent discoveryAgent;

    /**
     * 搜索到的设备列表
     */
    protected Vector remoteDeviceVector = new Vector();
    /**
     * 搜索到的服务信息列表
     */
    protected Vector serviceInfoVector = new Vector();
    /**
     * 搜索到的服务列表
     */
    protected Vector serviceRecordVector = new Vector();

    /**
     * 
     */
    // protected int connectType = 0;
    /**
     * 状态
     */
    protected int status = 0;

    /**
     * 是否支持蓝牙
     */
    protected boolean supportJSR82 = false;

    /**
     * 对象锁,控制设备搜索和服务搜索
     */
    private Object bluelock = new Object();

    /**
     * 过滤器
     */
    private Filter filter;

    /**
     * 预设设备
     */
    private String expectDevice;

    /**
     * 构造子
     */
    private BlueTooth()
    {
        try
        {
            Class.forName("javax.bluetooth.LocalDevice");
            supportJSR82 = true;
        }
        catch (Exception ex)
        {
            supportJSR82 = false;
        }
        try
        {
            // 获得本地设备
            localDevice = LocalDevice.getLocalDevice();
            // 获得本地设备代理
            discoveryAgent = localDevice.getDiscoveryAgent();
        }
        catch (Exception e)
        {
            supportJSR82 = false;
        }
    }

    /**
     * 获取单实例
     * 
     * @return 静态单实例
     */
    public static BlueTooth getInstance()
    {
        return instance;
    }

    /**
     * 搜索蓝牙设备
     * 
     * @return 搜索到的蓝牙设备
     */
    public Vector findDevices()
    {
        remoteDeviceVector.removeAllElements();
        try
        {
            // 启动搜索代理发现设备并与DiscoveryListener注册回调
            discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);
            // 设备搜索状态
            setStatus(STATUS_DEV_SEARCHING);
            // 设备搜索过程是异步的,这里需要同步搜索过程
            // 设备搜索完毕会通知主线程继续运行

            synchronized (bluelock)
            {
                // 加上while,break纯粹是为了规避findbugs检查
                while (status >= STATUS_READY && status < STATUS_DEV_SEARCH_FINISH)
                {
                    try
                    {
                        bluelock.wait();
                        // break;
                    }
                    catch (Exception e)
                    {
                        break;
                    }
                }
            }
        }
        catch (BluetoothStateException e)
        {
            setStatus(STATUS_DEV_SEARCH_ERROR);
        }
        return remoteDeviceVector;
    }

    /**
     * 获取手机匹配装置列表中的蓝牙设备集合
     * 
     * @return 搜索到的蓝牙设备
     */
    public Vector findDeviceInCache()
    {
        Vector vector = new Vector();
        RemoteDevice[] rds = discoveryAgent.retrieveDevices(DiscoveryAgent.CACHED);
        if (rds != null)
        {
            for (int i = 0; i < rds.length; i++)
            {
                vector.addElement(rds[i]);
            }

        }
        rds = discoveryAgent.retrieveDevices(DiscoveryAgent.PREKNOWN);
        if (rds != null)
        {
            for (int i = 0; i < rds.length; i++)
            {
                vector.addElement(rds[i]);
            }

        }
        return vector;
    }

    /**
     * 取消正在执行的设备搜索
     */
    public void cancelFindDevices()
    {
        if (status == STATUS_DEV_SEARCHING)
        {
            discoveryAgent.cancelInquiry(this);
        }
    }

    /**
     * 蓝牙设备发现时的回调方法<BR>
     * 每发现一个蓝牙装置,此方法将被调用一次。
     * 
     * @param btDevice 搜索到的蓝牙装置
     * @param cod 服务类,远程蓝牙装置的主设备类或附设备类
     * @see javax.bluetooth.DiscoveryListener#deviceDiscovered(javax.bluetooth.RemoteDevice,
     *      javax.bluetooth.DeviceClass)
     */

    public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod)
    {
        if (filter != null && !filter.match(btDevice))
        {
            return;
        }
        else
        {
            remoteDeviceVector.addElement(btDevice);
        }
        if (expectDevice != null && expectDevice.equals(btDevice.getBluetoothAddress()))
        {
            discoveryAgent.cancelInquiry(this);
        }
    }

    /**
     * 设备搜索结束时的回调方法<BR>
     * 
     * 
     * @param discType 搜索请求结束类型; 为INQUIRY_COMPLETED, INQUIRY_TERMINATED, 或INQUIRY_ERROR
     * @see javax.bluetooth.DiscoveryListener#inquiryCompleted(int)
     */

    public void inquiryCompleted(int discType)
    {
        if (discType == INQUIRY_COMPLETED)
        {
            setStatus(STATUS_DEV_SEARCH_FINISH);
        }
        else if (discType == INQUIRY_ERROR)
        {
            setStatus(STATUS_DEV_SEARCH_ERROR);
        }
        // 蓝牙搜索执行完毕,通知主线程继续
        synchronized (bluelock)
        {
            bluelock.notifyAll();
        }
    }

    /**
     * 搜索蓝牙设备提供的服务
     * 
     * @param device 远程蓝牙设备
     * @param uuids 搜索服务UUID数组
     * @return 搜索到的服务集合
     */
    public Vector findServices(RemoteDevice device, UUID[] uuids)
    {
        serviceInfoVector.removeAllElements();
        serviceRecordVector.removeAllElements();
        try
        {
            discoveryAgent.searchServices(new int[] {0x100 }, uuids, device, this);
            setStatus(STATUS_SER_SEARCHING);
        }
        catch (BluetoothStateException e)
        {
            setStatus(STATUS_SER_SEARCH_ERROR);
        }

        synchronized (bluelock)
        {
            // 加上while,break纯粹是为了规避findbugs检查
            while (status > STATUS_DEV_SEARCHING && status <= STATUS_SER_SEARCHING)
            {
                try
                {
                    bluelock.wait();
                    // break;
                }
                catch (InterruptedException e)
                {
                    break;
                }
            }
        }
        return serviceRecordVector;
    }

    /**
     * 搜索服务时找到服务的回调方法<BR>
     * [功能详细描述]
     * 
     * @param transID 服务搜索事务ID
     * @param servRecord 搜索到的服务记录数组
     * @see javax.bluetooth.DiscoveryListener#servicesDiscovered(int, javax.bluetooth.ServiceRecord[])
     */

    public void servicesDiscovered(int transID, ServiceRecord[] servRecord)
    {
        if (servRecord != null)
        {
            for (int i = 0; i < servRecord.length; i++)
            {
                DataElement serviceNameElement = servRecord[i].getAttributeValue(0x0100);
                String serviceName = (serviceNameElement.getValue().toString()).trim();
                ServiceInfo info = new ServiceInfo();
                info.name = serviceName;
                serviceInfoVector.addElement(info);
                serviceRecordVector.addElement(servRecord[i]);
            }
        }
    }

    /**
     * 搜索服务结束回调方法<BR>
     * 结束包含正常结束,手动终止或错误
     * 
     * @param transID 搜索事务ID
     * @param respCode 搜索响应码
     * @see javax.bluetooth.DiscoveryListener#serviceSearchCompleted(int, int)
     */

    public void serviceSearchCompleted(int transID, int respCode)
    {
        switch (respCode)
        {
            case DiscoveryListener.SERVICE_SEARCH_COMPLETED:
            case DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE:
            case DiscoveryListener.SERVICE_SEARCH_NO_RECORDS:
            case DiscoveryListener.SERVICE_SEARCH_TERMINATED:
            {
                setStatus(STATUS_SER_SEARCH_FINISH);
                break;
            }
            case DiscoveryListener.SERVICE_SEARCH_ERROR:
            {
                setStatus(STATUS_SER_SEARCH_ERROR);
                break;
            }
            default:
            {
                setStatus(STATUS_SER_SEARCH_FINISH);
                break;
            }
        }
        synchronized (bluelock)
        {
            bluelock.notifyAll();
        }
    }

    /**
     * 线程run方法<BR>
     * 搜索设备
     * 
     * @see java.lang.Runnable#run()
     */
    public void run()
    {
        if (supportJSR82)
        {
            findDevices();
        }
    }

    /**
     * 根据服务URL创建连接
     * 
     * @param url 从ServiceRecord中获取的服务URL
     * @return 创建的连接
     * @exception IOException 当创建连接失败时,抛出IO异常
     */
    public Connection getConnection(String url) throws IOException
    {
        Connection conn = null;
        try
        {
            setStatus(STATUS_CONNECTING);
            conn = Connector.open(url);
            setStatus(STATUS_CONNECT_OK);
            // RemoteDevice rd = RemoteDevice.getRemoteDevice(conn);
        }
        catch (IOException e)
        {
            setStatus(STATUS_CONNECT_FAIL);
            throw e;
        }
        return conn;
    }

    /**
     * 根据服务记录创建连接
     * 
     * @param service 搜索记录
     * @return 创建的连接
     * @exception IOException 当创建连接失败时,抛出IO异常
     */
    public Connection getConnection(ServiceRecord service) throws IOException
    {
        String url = service.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
        return getConnection(url);
    }

    // -----------------> getter & setter

    /**
     * 获取搜索到的蓝牙设备列表<br />
     * 如果要获取最终的设备列表,需要在status=STATUS_DEV_SEARCH_FINISH时,再调用此方法
     * 
     * @return 搜索到的蓝牙设备列表
     */
    public Vector getRemoteDeviceVector()
    {
        return remoteDeviceVector;
    }

    /**
     * 获取搜索到的服务列表
     * 
     * @return 搜索到的ServiceRecord列表
     */
    public Vector getServiceRecordVector()
    {
        return serviceRecordVector;
    }

    /**
     * 获取搜索到的服务信息列表
     * 
     * @return 搜索到的ServiceRecord信息列表
     */
    public Vector getServiceInfoVector()
    {
        return serviceInfoVector;
    }

    /**
     * 获取当前状态
     * 
     * @return 状态
     */
    public int getStatus()
    {
        return status;
    }

    /**
     * 设置状态
     * 
     * @param status 要设置的状态
     */
    public void setStatus(int status)
    {
        this.status = status;
    }

    /**
     * 判断是否支持jsr82规范
     * 
     * @return 是否支持蓝牙
     */
    public boolean isSupportJSR82()
    {
        return supportJSR82;
    }

    /**
     * 设置搜索过滤器
     * 
     * @param filter 搜索设备时的过滤器
     */
    public void setFilter(Filter filter)
    {
        this.filter = filter;
    }

    /**
     * 获取设备过滤器
     * 
     * @return 设备过滤器
     */
    public Filter getFilter()
    {
        return filter;
    }

    /**
     * 设备搜索过滤器<BR>
     * 如果符合匹配条件,则将搜索到的设备加入搜索结果集合当中
     * 
     * @author Adminstrator
     * @version V1.0
     */
    public static abstract class Filter
    {
        /**
         * 判断设备是否符合过滤规则
         * 
         * @param device 搜索到的设备
         * @return 是否符合过滤规则
         */
        public abstract boolean match(RemoteDevice device);
    }
}