📄 bluetoothdiscovery.java
字号:
* @return Returns a list of connected devices.
* @throws BluetoothStateException Is thrown when a request is made to the Bluetooth system that the system cannot support in its present state.
* @throws InterruptedException Thrown when a thread is waiting, sleeping, or otherwise paused for a long time and another thread interrupts it using the interrupt method in class Thread.
* @throws IOException Signals that an I/O exception of some sort has occurred. This class is the general class of exceptions produced by failed or interrupted I/O operations.
*/
public BluetoothConnection[] searchService( int st )
throws BluetoothStateException, InterruptedException, IOException
{
StreamConnection con;
DataElement de;
String rname;
// Reset search transaction id
serviceSearchTransId = -1;
// store search type
searchType = st;
if( searchType == SEARCH_ALL_DEVICES_SELECT_SEVERAL )
{ // if user should select several devices
if( maxDevices == 1 )
{ // but only point-to-point possible
// So switch back to "SELECT_ONE"
searchType = SEARCH_ALL_DEVICES_SELECT_ONE;
}
}
// Initialize
foundServiceRecords = new Vector();
urlStrings = new Vector();
// obtain discovery object which will be used for inquiry
discoveryAgent = localDevice.getDiscoveryAgent();
// Create Discovery Listener (Inquiry Listener) Object
listener = new Listener();
// Show progress bar for Inquiry
progressBar = new InqProgressBar( "Search Devices...", 105 );
// Init warning string
warning = "";
// startInquiry is asynchronous. Here we have to wait until it "notify"s us.
synchronized( block_c )
{ // start the inquiry on LIAC only
discoveryAgent.startInquiry( DiscoveryAgent.LIAC, listener );
// wait
block_c.wait();
}
// Release List object
deviceList = null;
// Stop progress bar
if( progressBar != null )
{
progressBar.stop();
}
// Check if service or devices not found and alert to user
if( ! warning.equals( "" ) )
{ // Do 2 secs alert
Alert al = new Alert( null, warning, null, AlertType.INFO );
// Show 2 seconds
al.setTimeout( 2000 );
display.setCurrent( al );
// wait
synchronized( al )
{
try
{
al.wait( 2000 );
}
catch(InterruptedException e )
{
// Shouldn't happen in MIDP
}
}
}
// Create list
btConnections = new BluetoothConnection[urlStrings.size()];
// Check if devices have been found
if( urlStrings.size() > 0 )
{ // connect only if devices have been found
// Start connection progress bar
progressBar = new PageProgressBar( "Connecting...", urlStrings.size() );
// Connect all devices
for( int i=0; i<urlStrings.size(); i++ )
{ // Retrieve remote name
de = ((ServiceRecord)foundServiceRecords.elementAt(i)).getAttributeValue( SERVICE_NAME_BASE_LANGUAGE );
rname = (String) de.getValue();
// Update progress bar
((PageProgressBar)progressBar).nextDevice();
btConnections[i] = new BluetoothConnection( (String) urlStrings.elementAt(i), localName, rname );
// Send name to remote device
btConnections[i].writeString( localName );
}
// Stop (connecting) progress bar
progressBar.stop();
}
// Delete progressBar
progressBar = null;
// reset listener
listener = null;
return btConnections;
}
/** Starts the server and register the service.
* Waits until someone connects to this service.
* @return A list containing 1 element which is the connection that has been
* created from a remote device to this device. In case there has been a connection error
* a list containing 1 element which is null is returned.
* @throws BluetoothStateException Is thrown when a request is made to the Bluetooth system that the system cannot support in its present state.
* @throws InterruptedException Thrown when a thread is waiting, sleeping, or otherwise paused for a long time and another thread interrupts it using the interrupt method in class Thread.
* @throws IOException Signals that an I/O exception of some sort has occurred. This class is the general class of exceptions produced by failed or interrupted I/O operations.
*/
public BluetoothConnection[] waitOnConnection()
throws BluetoothStateException, IOException, InterruptedException
{
acceptAndOpenThread t;
String ServiceName;
// Save Discoverability Mode
saveDiscoverability();
// Go in Limited Inquiry scan mode
localDevice.setDiscoverable( DiscoveryAgent.LIAC );
// Call connector.open to create Notifier object
notifier = (StreamConnectionNotifier) Connector.open( "btspp://localhost:" + serviceUUID + ";name=" + localName + ";authorize=false;authenticate=false;encrypt=false" );
// Show text box with possibility to cancel the server session.
setTitle( "Waiting" );
setString( "Waiting for someone to connect..." );
setTimeout( FOREVER );
addCommand( new Command( "Cancel", Command.CANCEL, 1 ) );
setCommandListener( this );
display.setCurrent( this );
// Spawn new thread which does acceptandopen
t = new acceptAndOpenThread();
// wait on thread (until someone connects)
synchronized( block_s )
{
// Start acceptAndOpen
t.start();
// wait
block_s.wait();
}
// Clear Notifier (is already closed)
notifier = null;
// restore discoverability mode
restoreDiscoverability();
// return the connection
return btConnections;
}
// Inner class
// Updates the inquiry progress bar/gauge based on a timer.
private class InqProgressBar
extends TimerTask
{
// Gauge object to update.
/** Reference to the gauge object.
*/
protected Gauge gauge;
/**
* Reference to the timer.
*/
protected Timer tm;
/**
* Constructor
* @param ga Gauge object that should be updated.
*/
private InqProgressBar( String title, int max )
{
// Show text box with possibility to cancel the discovery
// Create Gauge object to show progress of inquiry
// Create the gauge, exit and stop command
gauge = new Gauge( title, false, max, 0 );
Command cmStop = new Command( "Cancel", Command.CANCEL, 1 );
// Create the form, add gauge & stop command, listen for events
Form f = new Form("");
f.append( gauge );
f.addCommand( cmStop );
f.setCommandListener( root );
display.setCurrent( f );
// Start timer that fires off every 100 ms
tm = new Timer();
tm.scheduleAtFixedRate( this, 0, 100);
}
/**
* The run method.
*/
public void run()
{
int time;
// add one second
time = gauge.getValue() + 1;
// Is current value of gauge less than the max?
if( time > gauge.getMaxValue() )
{ // Begin at 0
time = 0;
}
// Store new value
gauge.setValue( time );
}
/**
* Stops the timer
*/
protected void stop()
{
// Stop the timer
cancel();
tm.cancel();
}
}
// Inner class
// Updates the page progress bar/gauge based on a timer.
private class PageProgressBar
extends InqProgressBar
{
static final int PAGE_TIME = 30; // in 1/10 secs, 3 secs
private int timer_max;
/**
* Constructor
* @param ga Gauge object that should be updated.
*/
private PageProgressBar( String str, int countDev )
{
super( str, countDev*PAGE_TIME );
// Set first timer_max value
timer_max = 0;
}
/**
* The run method.
*/
public final void run()
{
int time;
// add one second
time = gauge.getValue() + 1;
// Is current value of gauge less than the max?
if( time > timer_max )
{ // Stop
time = timer_max;
}
// Store new value
gauge.setValue( time );
}
/**
* Start progress bar for next device.
*/
public void nextDevice()
{
// Set current value
gauge.setValue( timer_max );
// Stop the timer
timer_max += PAGE_TIME;
}
}
// Inner class: Listener
// Listens on events like deviceDiscovered or servicesDiscovered.
private class Listener
implements DiscoveryListener
{
private Vector cached_devices;
ServiceRecord currServRec;
/** Constructor
*/
public Listener()
{
// Initialize
cached_devices = new Vector();
}
/**
* Called when a device is found during an inquiry. An inquiry
* searches for devices that are discoverable. The same device may
* be returned multiple times.
*
* @see DiscoveryAgent#startInquiry
*
* @param btDevice the device that was found during the inquiry
*
* @param cod the service classes, major device class, and minor
* device class of the remote device
*
*/
public void deviceDiscovered( RemoteDevice btDevice, DeviceClass cod )
{
// Filter CoD: Ie. only store devices in case the device is
// a phone. That also prevents from the link level security problem:
// Phone's do not use link level security.
// (Because LIAC has been used for inquiry it is anyway very unlikely
// that we run into the link level security problem.)
if( ! CONCEPT_SDK_BUILD )
{ // Concept SDK returns wrong values for CoD
if( cod.getMajorDeviceClass() != MAJOR_DEVICE_CLASS_PHONE )
{ // return in case it's not a phone
return;
}
}
// It's another phone, so store it in the list
if( ! cached_devices.contains( btDevice ) )
{ // But only if it is not already in the list (same device might be reported more than once)
cached_devices.addElement( btDevice );
}
}
/**
* Called when an inquiry is completed. The <code>discType</code> will be
* <code>INQUIRY_COMPLETED</code> if the inquiry ended normally or
* <code>INQUIRY_TERMINATED</code> if the inquiry was canceled by a call to
* <code>DiscoveryAgent.cancelInquiry()</code>. The <code>discType</code>
* will be <code>INQUIRY_ERROR</code> if an error occurred while
* processing the inquiry causing the inquiry to end abnormally.
*
* @see #INQUIRY_COMPLETED
* @see #INQUIRY_TERMINATED
* @see #INQUIRY_ERROR
*
* @param discType the type of request that was completed; either
* <code>INQUIRY_COMPLETED</code>, <code>INQUIRY_TERMINATED</code>, or
* <code>INQUIRY_ERROR</code>
*/
public void inquiryCompleted( int discType )
{
if( discType == INQUIRY_COMPLETED )
{ // Check if devices have been found
if( cached_devices.size() == 0 )
{ // No device found
warning = "No devices found!";
}
else
{ // Stop Inquiry progress bar
progressBar.stop();
// Start service search progress bar
progressBar = new PageProgressBar( "Search Service...", cached_devices.size() );
// start service search
nextDeviceServiceSearch();
return;
}
}
// In case inquiry was terminated or no device has been found
// then return to main function
synchronized( block_c )
{
block_c.notifyAll();
}
// Note: progressBar is anyway stopped by searchService method
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -