Bluecove Bluetooth remote device service discovery example

UPDATED: 29 July 2014
BlueCove + Bluetooth + 700x300.png

BlueCove
BlueCove is Java library for bluetooth. Its used to interact with Bluetooth devices using Java. BlueCove currently supports Mac OS X, WIDCOMM, BlueSoleil and Microsoft Bluetooth stack. Current version is 2.1.0. Read more on official website http://bluecove.org

Today I'm going to demonstrate "How to use BlueCove to search near by Bluetooth devices?" and "How to find Bluetooth device services using BlueCove".

RemoteDeviceDiscovery
RemoteDeviceDiscovery class is used to find paired and near by devices.
import java.util.Enumeration;
import java.util.Vector;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;

public class RemoteDeviceDiscovery {

    public Vector getDevices() {
        /* Create Vector variable */
        final Vector devicesDiscovered = new Vector();
        try {
            final Object inquiryCompletedEvent = new Object();
            /* Clear Vector variable */
            devicesDiscovered.clear();

            /* Create an object of DiscoveryListener */
            DiscoveryListener listener = new DiscoveryListener() {

                public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
                    /* Get devices paired with system or in range(Without Pair) */
                    devicesDiscovered.addElement(btDevice);
                }

                public void inquiryCompleted(int discType) {
                    /* Notify thread when inquiry completed */
                    synchronized (inquiryCompletedEvent) {
                        inquiryCompletedEvent.notifyAll();
                    }
                }

                /* To find service on bluetooth */
                public void serviceSearchCompleted(int transID, int respCode) {
                }

                /* To find service on bluetooth */
                public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
                }
            };

            synchronized (inquiryCompletedEvent) {
                /* Start device discovery */
                boolean started = LocalDevice.getLocalDevice().getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, listener);
                if (started) {
                    System.out.println("wait for device inquiry to complete...");
                    inquiryCompletedEvent.wait();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        /* Return list of devices */
        return devicesDiscovered;
    }
}

ServicesSearch
ServicesSearch class used to find specific service on Bluetooth device. Each service identified using UUID (Universally unique identifier). All UUID listed on https://www.bluetooth.org/en-us/specification/assigned-numbers/service-discovery . Replace your required UUID in following code.
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.bluetooth.*;

public class ServicesSearch {

    /** 
     * UUID used to find specific service supported by bluetooth device
     * https://www.bluetooth.org/en-us/specification/assigned-numbers/service-discovery
     * Find UUIDs for all types of bluetooth services.
     */
    /* To find push object service */
    private UUID OBEX_OBJECT_PUSH_PROFILE = new UUID(0x1105);
    /* To find file transfer service */
    private UUID OBEX_FILE_TRANSFER_PROFILE = new UUID(0x1106);
    /* To find hands free service */
    private UUID HANDS_FREE = new UUID(0x111E);
    /* Get URL attribute from bluetooth service */
    private int URL_ATTRIBUTE = 0X0100;
    
    public Map<String, List<String>> getBluetoothDevices() {        
        /**
         * Find service on bluetooth device 
         * Note: In following line you can use one service at a time. I'm new to bluetooth programming it might me wrong perception.
         * UUID[] searchUuidSet = new UUID[]{OBEX_FILE_TRANSGER_PROFILE};
         * 
         * CORRECT: UUID[] searchUuidSet = new UUID[]{OBEX_FILE_TRANSGER_PROFILE};
         * WRONG: UUID[] searchUuidSet = new UUID[]{OBEX_FILE_TRANSGER_PROFILE, OBEX_OBJECT_PUSH_PROFILE};
         */
        /* Initialize UUID Array */
        UUID[] searchUuidSet = new UUID[]{HANDS_FREE};
        final Object serviceSearchCompletedEvent = new Object();
        int[] attrIDs = new int[]{URL_ATTRIBUTE};
        
        /* Create an object to get list of devices in range or paired */
        RemoteDeviceDiscovery remoteDeviceDiscovery = new RemoteDeviceDiscovery();
        /* Create map to return Bluetooth device address, name and URL */
        final Map<String, List<String>> mapReturnResult = new HashMap<String, List<String>>(); 

        try {
            /* Create an object of DiscoveryListener */
            DiscoveryListener listener = new DiscoveryListener() {

                /* To find bluetooth devices */
                public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
                }

                /* To find bluetooth devices */
                public void inquiryCompleted(int discType) {
                }

                /* Find service URL of bluetooth device */
                public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
                    for (int i = 0; i < servRecord.length; i++) {
                        /* Find URL of bluetooth device */
                        String url = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
                        if (url == null) {
                            continue;
                        }
                        String temporaryString = "";
                        /* Get object of bluetooth device */
                        RemoteDevice rd = servRecord[i].getHostDevice();
                        /* Get attribute from ServiceRecord */
                        DataElement serviceName = servRecord[i].getAttributeValue(URL_ATTRIBUTE);
                        if (serviceName != null) {         
                            temporaryString = serviceName.getValue() + "\n" + url;
                            /* Put it in map */
                            mapReturnResult.get(rd.getBluetoothAddress()).add(temporaryString);
                        } else {
                            temporaryString = "Uknown service \n" + url;
                            /* Put it in map */
                            mapReturnResult.get(rd.getBluetoothAddress()).add(temporaryString);
                        }
                    }
                }

                public void serviceSearchCompleted(int transID, int respCode) {
                    /* Notify thread when search completed */
                    synchronized (serviceSearchCompletedEvent) {
                        serviceSearchCompletedEvent.notifyAll();
                    }
                }
            };

            /* Get list of bluetooth device from class RemoteDeviceDiscovery */
            for (Enumeration en = remoteDeviceDiscovery.getDevices().elements(); en.hasMoreElements();) {
                /* Get RemoteDevice object */
                RemoteDevice btDevice = (RemoteDevice) en.nextElement();
                /* Create list to return details */
                List<String> listDeviceDetails = new ArrayList<String>();
                
                try {
                    /* Add bluetooth device name and address in list */
                    listDeviceDetails.add(btDevice.getFriendlyName(false));
                    listDeviceDetails.add(btDevice.getBluetoothAddress());
                } catch (Exception e) {
                }
                
                /* Put bluetooth device details in map */
                mapReturnResult.put(btDevice.getBluetoothAddress(), listDeviceDetails);
                synchronized (serviceSearchCompletedEvent) {
                    LocalDevice.getLocalDevice().getDiscoveryAgent().searchServices(attrIDs, searchUuidSet, btDevice, listener);
                    serviceSearchCompletedEvent.wait();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        /* Return bluetooth devices detail */
        return mapReturnResult;
    }
}

BluetoothDevices
BluetoothDevices is simple JFrame used to give Uter Interface for program. Its created in NetBeans IDE, You may find some code unexplained which is generated by IDE.
import com.javaquery.bluetooth.ServicesSearch;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.UIManager;

public class BluetoothDevices extends javax.swing.JFrame {

    /* DefaultListModel to attach it with JList */
    private DefaultListModel defaultModel;
    /* Map to get device details list */
    private Map<String, List<String>> mapReturnResult = new HashMap<String, List<String>>();
    /* Map to identify device on user click of JList */
    private Map<Integer, List<String>> mapDevicePosition = new HashMap<Integer, List<String>> ();

    public BluetoothDevices() {
        initComponents();
        defaultModel = new DefaultListModel();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        JListBluetoothDevices = new javax.swing.JList();
        lblDeviceName = new javax.swing.JLabel();
        lblRuntimeDeviceName = new javax.swing.JLabel();
        lblDeviceAddress = new javax.swing.JLabel();
        lblRuntimeDeviceAddress = new javax.swing.JLabel();
        lblServiceDetails = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        JTextAreaServiceDetails = new javax.swing.JTextArea();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Bluecove Bluetooth Discovery");
        setResizable(false);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowOpened(java.awt.event.WindowEvent evt) {
                formWindowOpened(evt);
            }
        });

        JListBluetoothDevices.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                JListBluetoothDevicesMouseClicked(evt);
            }
        });
        jScrollPane1.setViewportView(JListBluetoothDevices);

        lblDeviceName.setText("Bluetooth Device Name");

        lblDeviceAddress.setText("Bluetooth Device Address");

        lblServiceDetails.setText("Service Details");

        JTextAreaServiceDetails.setColumns(20);
        JTextAreaServiceDetails.setRows(5);
        jScrollPane2.setViewportView(JTextAreaServiceDetails);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 158, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(lblDeviceName)
                            .addComponent(lblDeviceAddress))
                        .addGap(73, 73, 73)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(lblRuntimeDeviceAddress)
                            .addComponent(lblRuntimeDeviceName, javax.swing.GroupLayout.PREFERRED_SIZE, 144, javax.swing.GroupLayout.PREFERRED_SIZE)))
                    .addComponent(lblServiceDetails)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 475, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 185, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(lblDeviceName)
                            .addComponent(lblRuntimeDeviceName))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(lblDeviceAddress)
                            .addComponent(lblRuntimeDeviceAddress))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(lblServiceDetails)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jScrollPane2, 0, 0, Short.MAX_VALUE)))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

 /* Search for bluetooth device when window opened */
    private void formWindowOpened(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowOpened
        int intDevicePosition = 0;
        JListBluetoothDevices.setModel(defaultModel);        

        /* Create an object of ServicesSearch */
        ServicesSearch ss = new ServicesSearch();
        /* Get bluetooth device details */
        mapReturnResult = ss.getBluetoothDevices();

        /* Add devices in JList */
        for (Map.Entry<String, List<String>> entry : mapReturnResult.entrySet()) {            
            defaultModel.addElement(entry.getValue().get(0));
            mapDevicePosition.put(intDevicePosition, entry.getValue());
            intDevicePosition++;
        }
    }//GEN-LAST:event_formWindowOpened

 /* On click of any item in List Box */
    private void JListBluetoothDevicesMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_JListBluetoothDevicesMouseClicked
  /* Get bluetooth device details from temporary list */
        List<String> tmpDeviceDetails = mapDevicePosition.get(JListBluetoothDevices.getSelectedIndex());
  /* Set bluetooth device name */
        lblRuntimeDeviceName.setText(tmpDeviceDetails.get(0));
  /* Set bluetooth device Address */
        lblRuntimeDeviceAddress.setText(tmpDeviceDetails.get(1));       
        
        if(tmpDeviceDetails.size() > 2 && tmpDeviceDetails.get(2) != null){
   /* Set bluetooth device service name and URL */
            JTextAreaServiceDetails.setText(tmpDeviceDetails.get(2));
        }else{
            JTextAreaServiceDetails.setText("Service not found");
        }
    }//GEN-LAST:event_JListBluetoothDevicesMouseClicked

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                 /* To set new look and feel */
                JFrame.setDefaultLookAndFeelDecorated(true);
                try {
                    /**
                     * Change look and feel of JFrame to Nimbus 
                     * For other look and feel check
      * http://www.javaquery.com/2013/06/how-to-applyset-up-swing-look-and-feel.html
                     */
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
                } catch (Exception ex) {
                   ex.printStackTrace();
                }
                /* Create an object of BluetoothDevices */
                BluetoothDevices bluetoothDevicesFrame = new BluetoothDevices();
                /* make BluetoothDevices visible */
                bluetoothDevicesFrame.setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JList JListBluetoothDevices;
    private javax.swing.JTextArea JTextAreaServiceDetails;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JLabel lblDeviceAddress;
    private javax.swing.JLabel lblDeviceName;
    private javax.swing.JLabel lblRuntimeDeviceAddress;
    private javax.swing.JLabel lblRuntimeDeviceName;
    private javax.swing.JLabel lblServiceDetails;
    // End of variables declaration//GEN-END:variables
}

Downloads
NetBeans Project: https://drive.google.com/open?id=0B0ioAuPvwwCCUFJMMEllTE5KQVk
Driver: https://drive.google.com/open?id=0B0ioAuPvwwCCRVpzNmIwOS1kMHM


0 comments :