📄 btimageclient.java
字号:
/*
* @(#)BTImageClient.java 1.1 04/04/24
*
* Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms
*/
package example.bluetooth.demo;
// jsr082 API
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;
// midp/cldc API
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.lcdui.Image;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* Initialize BT device, search for BT services,
* presents them to user and picks his/her choice,
* finally download the choosen image and present
* it to user.
*
* @author Vladimir K. Beliaev
* @version 1.1, 04/24/04
*/
final class BTImageClient implements Runnable, DiscoveryListener {
/** Describes this server - note, it's a "short" UUID. */
private static final UUID PICTURES_SERVER_UUID = new UUID(0x12345);
/** The attribute id of the record item with images names. */
private static final int IMAGES_NAMES_ATTRIBUTE_ID = 0x4321;
/** Shows the engine is ready to work. */
private static final int READY = 0;
/** Shows the engine is searching bluetooth devices. */
private static final int DEVICE_SEARCH = 1;
/** Shows the engine is searching bluetooth services. */
private static final int SERVICE_SEARCH = 2;
/** Keeps the current state of engine. */
private int state = READY;
/** Keeps the discovery agent reference. */
private DiscoveryAgent discoveryAgent;
/** Keeps the parent reference to process specific actions. */
private ClientMIDlet parent;
/** Becomes 'true' when this component is finilized. */
private boolean isClosed;
/** Proccess the search/download requests. */
private Thread processorThread;
/** Collects the remote devices found during a search. */
private Vector /* RemoteDevice */ devices = new Vector();
/** Collects the services found during a search. */
private Vector /* ServiceRecord */ records = new Vector();
/** Keeps the device discovery return code. */
private int discType;
/** Keeps the services search IDs (just to be able to cancel them). */
private int[] searchIDs;
/** Keeps the image name to be load. */
private String imageNameToLoad;
/** Keeps the table of {name, Service} to process the user choice. */
private Hashtable base = new Hashtable();
/** Informs the thread the download should be canceled. */
private boolean isDownloadCanceled;
/** Optimization: keeps service search patern. */
private UUID[] uuidSet;
/** Optimization: keeps attributes list to be retrieved. */
private int[] attrSet;
/**
* Constructs the bluetooth server, but it is initialized
* in the different thread to "avoid dead lock".
*/
BTImageClient(ClientMIDlet parent) {
this.parent = parent;
// we have to initialize a system in different thread...
processorThread = new Thread(this);
processorThread.start();
}
/**
* Process the search/download requests.
*/
public void run() {
// initialize bluetooth first
boolean isBTReady = false;
try {
// create/get a local device and discovery agent
LocalDevice localDevice = LocalDevice.getLocalDevice();
discoveryAgent = localDevice.getDiscoveryAgent();
// remember we've reached this point.
isBTReady = true;
} catch (Exception e) {
System.err.println("Can't initialize bluetooth: " + e);
}
parent.completeInitialization(isBTReady);
// nothing to do if no bluetooth available
if (!isBTReady) {
return;
}
// initialize some optimization variables
uuidSet = new UUID[2];
// ok, we are interesting in btspp services only
uuidSet[0] = new UUID(0x1101);
// and only known ones, that alllows pictures
uuidSet[1] = PICTURES_SERVER_UUID;
// we need an only service attribute actually
attrSet = new int[1];
// it's "images names" one
attrSet[0] = IMAGES_NAMES_ATTRIBUTE_ID;
// start processing the images search/download
processImagesSearchDownload();
}
/**
* Invoked by system when a new remote device is found -
* remember the found device.
*/
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
// same device may found several times during single search
if (devices.indexOf(btDevice) == -1) {
devices.addElement(btDevice);
}
}
/**
* Invoked by system when device discovery is done.
* <p>
* Use a trick here - just remember the discType
* and process its evaluation in another thread.
*/
public void inquiryCompleted(int discType) {
this.discType = discType;
synchronized (this) {
notify();
}
}
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
for (int i = 0; i < servRecord.length; i++) {
records.addElement(servRecord[i]);
}
}
public void serviceSearchCompleted(int transID, int respCode) {
// first, find the service search transaction index
int index = -1;
for (int i = 0; i < searchIDs.length; i++) {
if (searchIDs[i] == transID) {
index = i;
break;
}
}
// error - unexpected transaction index
if (index == -1) {
System.err.println("Unexpected transaction index: " + transID);
// FIXME: process the error case
} else {
searchIDs[index] = -1;
}
/*
* Actually, we do not care about the response code -
* if device is not reachable or no records, etc.
*/
// make sure it was the last transaction
for (int i = 0; i < searchIDs.length; i++) {
if (searchIDs[i] != -1) {
return;
}
}
// ok, all of the transactions are completed
synchronized (this) {
notify();
}
}
/** Sets the request to search the devices/services. */
void requestSearch() {
synchronized (this) {
notify();
}
}
/** Cancel's the devices/services search. */
void cancelSearch() {
synchronized (this) {
if (state == DEVICE_SEARCH) {
discoveryAgent.cancelInquiry(this);
} else if (state == SERVICE_SEARCH) {
for (int i = 0; i < searchIDs.length; i++) {
discoveryAgent.cancelServiceSearch(searchIDs[i]);
}
}
}
}
/** Sets the request to search the devices/services. */
void requestLoad(String name) {
synchronized (this) {
imageNameToLoad = name;
notify();
}
}
/** Cancel's the image downlaod. */
void cancelLoad() {
/*
* The image download process is done by
* this class's thread (not by a system one),
* so no need to wake up the current thread -
* it's running already.
*/
isDownloadCanceled = true;
}
/**
* Destroy a work with bluetooth - exits the accepting
* thread and close notifier.
*/
void destroy() {
synchronized (this) {
isClosed = true;
isDownloadCanceled = true;
notify();
// FIXME: implement me
}
// wait for acceptor thread is done
try {
processorThread.join();
} catch (InterruptedException e) {} // ignore
}
/**
* Processes images seach/download until component is closed
* or system error has happen.
*/
private synchronized void processImagesSearchDownload() {
while (!isClosed) {
// wait for new search request from user
state = READY;
try {
wait();
} catch (InterruptedException e) {
System.err.println("Unexpected interuption: " + e);
return;
}
// check the component is destroyed
if (isClosed) {
return;
}
// search for devices
if (!searchDevices()) {
return;
} else if (devices.size() == 0) {
continue;
}
// search for services now
if (!searchServices()) {
return;
} else if (records.size() == 0) {
continue;
}
// ok, something was found - present the result to user now
if (!presentUserSearchResults()) {
// services are found, but no names there
continue;
}
// the several download requests may be processed
while (true) {
// this download is not canceled, right?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -