/* * ServerScreen.java * * Copyright � 1998-2011 Research In Motion Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Note: For the sake of simplicity, this sample application may not leverage * resource bundles and resource strings. However, it is STRONGLY recommended * that application developers make use of the localization features available * within the BlackBerry development platform to ensure a seamless application * experience across a variety of languages and geographies. For more information * on localizing your application, please refer to the BlackBerry Java Development * Environment Development Guide associated with this release. */ package com.rim.samples.device.bluetoothjsr82demo; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import javax.bluetooth.BluetoothStateException; import javax.bluetooth.DiscoveryAgent; import javax.bluetooth.L2CAPConnection; import javax.bluetooth.L2CAPConnectionNotifier; import javax.bluetooth.LocalDevice; import javax.bluetooth.UUID; import javax.microedition.io.Connector; import javax.microedition.io.StreamConnection; import javax.microedition.io.StreamConnectionNotifier; import javax.obex.HeaderSet; import javax.obex.Operation; import javax.obex.ResponseCodes; import javax.obex.ServerRequestHandler; import javax.obex.SessionNotifier; import net.rim.device.api.command.Command; import net.rim.device.api.command.CommandHandler; import net.rim.device.api.command.ReadOnlyCommandMetadata; import net.rim.device.api.ui.Field; import net.rim.device.api.ui.MenuItem; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.component.RichTextField; import net.rim.device.api.ui.container.MainScreen; import net.rim.device.api.util.StringProvider; /** * Server Screen class for the BluetoothJSR82Demo application */ public final class ServerScreen extends MainScreen { private static final String SERVICE_NAME_SPP = "SPPDemo"; private static final String SERVICE_NAME_OPP = "OPPDemo"; private static final String SERVICE_NAME_L2CAP = "L2CAPDemo"; private final int _uuid; private final RichTextField _statusField; /** * Creates a new ServerScreen object */ public ServerScreen(final int uuid) { setTitle("Bluetooth JSR82 Demo Server"); _uuid = uuid; _statusField = new RichTextField(Field.NON_FOCUSABLE); add(_statusField); final MenuItem infoScreen = new MenuItem(new StringProvider("Info Screen"), 0x230010, 0); infoScreen.setCommand(new Command(new CommandHandler() { /** * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, * Object) */ public void execute(final ReadOnlyCommandMetadata metadata, final Object context) { UiApplication.getUiApplication().pushScreen(new InfoScreen()); } })); addMenuItem(infoScreen); try { // Make the device discoverable final LocalDevice device = LocalDevice.getLocalDevice(); // Store the current mode so it can be restored later final int mode = device.getDiscoverable(); if (mode != DiscoveryAgent.GIAC) { device.setDiscoverable(DiscoveryAgent.GIAC); } switch (_uuid) { case BluetoothJSR82Demo.SPP_UUID: final SPPServerThread sppThread = new SPPServerThread(); sppThread.start(); break; case BluetoothJSR82Demo.OPP_UUID: final OPPServerThread oppThread = new OPPServerThread(); oppThread.start(); break; case BluetoothJSR82Demo.L2CAP_UUID: final L2CAPServerThread l2capThread = new L2CAPServerThread(); l2capThread.start(); break; } } catch (final BluetoothStateException bse) { BluetoothJSR82Demo.errorDialog(bse.toString()); } } /** * Updates the text displayed by the status field * * @param message * The text to be displayed */ public void updateStatus(final String message) { UiApplication.getUiApplication().invokeLater(new Runnable() { /** * @see java.lang.Runnable#run() */ public void run() { _statusField.setText(_statusField.getText() + "\n" + message); } }); } // SPP SERVER THREAD // ******************************************************************* /** * A thread that opens an SPP connection, awaits client requests, accepts * incoming messages, and sends a response. */ private class SPPServerThread extends Thread { /** * @see java.lang.Runnable#run() */ public void run() { try { StreamConnection connection = null; DataOutputStream os = null; DataInputStream is = null; try { final UUID uuid = new UUID(_uuid); final LocalDevice local = LocalDevice.getLocalDevice(); updateStatus("[SERVER] Device Address: " + local.getBluetoothAddress()); updateStatus("[SERVER] Device Name: " + local.getFriendlyName()); updateStatus("[SERVER] Listening for Client..."); // Open a connection and wait for client requests final StreamConnectionNotifier service = (StreamConnectionNotifier) Connector .open("btspp://localhost:" + uuid + ";name=" + SERVICE_NAME_SPP); connection = service.acceptAndOpen(); updateStatus("[SERVER] SPP session created"); // Read a message is = connection.openDataInputStream(); final byte[] buffer = new byte[1024]; final int readBytes = is.read(buffer); final String receivedMessage = new String(buffer, 0, readBytes); updateStatus("[SERVER] Message received: " + receivedMessage); // Send a message final String message = "\nJSR-82 SERVER says hello!"; updateStatus("[SERVER] Sending message...."); os = connection.openDataOutputStream(); os.write(message.getBytes()); os.flush(); } finally { os.close(); is.close(); updateStatus("[SERVER] SPP session closed"); } } catch (final IOException ioe) { BluetoothJSR82Demo.errorDialog(ioe.toString()); } } } // L2CAP SERVER THREAD // ******************************************************************* /** * A thread that implements an L2CAP server which accepts a single line * message from an L2CAP client and sends a single line response back to the * client. */ private class L2CAPServerThread extends Thread { /** * @see java.lang.Runnable#run() */ public void run() { try { L2CAPConnection connection = null; try { final UUID uuid = new UUID(_uuid); final LocalDevice local = LocalDevice.getLocalDevice(); updateStatus("[SERVER] Device Address: " + local.getBluetoothAddress()); updateStatus("[SERVER] Device Name: " + local.getFriendlyName()); updateStatus("[SERVER] Listening for Client..."); // Open a connection and wait for client requests final L2CAPConnectionNotifier service = (L2CAPConnectionNotifier) Connector .open("btl2cap://localhost:" + uuid + ";name=" + SERVICE_NAME_L2CAP); connection = service.acceptAndOpen(); updateStatus("[SERVER] L2CAP connection established"); // Read a message final byte[] buffer = new byte[1024]; final int readBytes = connection.receive(buffer); final String receivedMessage = new String(buffer, 0, readBytes); updateStatus("[SERVER] Message received: " + receivedMessage); // Send a message final String message = "\nJSR-82 SERVER says hello!"; updateStatus("[SERVER] Sending message...."); connection.send(message.getBytes()); } finally { connection.close(); updateStatus("[SERVER] L2CAP session closed"); } } catch (final IOException ioe) { BluetoothJSR82Demo.errorDialog(ioe.toString()); } } } // OPP SERVER THREAD // ******************************************************************* /** * A thread that opens an OPP connection, awaits client requests, accepts * incoming messages, and sends a response. */ private class OPPServerThread extends Thread { /** * @see java.lang.Runnable#run() */ public void run() { try { final UUID uuid = new UUID(_uuid); final LocalDevice local = LocalDevice.getLocalDevice(); updateStatus("[SERVER] Device Address: " + local.getBluetoothAddress()); updateStatus("[SERVER] Device Name: " + local.getFriendlyName()); // Open a connection and wait for client requests final SessionNotifier sessionNotifier = (SessionNotifier) Connector.open("btgoep://localhost:" + uuid + ";name=" + SERVICE_NAME_OPP); updateStatus("[SERVER] Waiting for Client to connect..."); sessionNotifier.acceptAndOpen(new ObexServerRequestHandler()); } catch (final IOException ioe) { BluetoothJSR82Demo.errorDialog(ioe.toString()); } } } /** * A class that handles incoming requests from a connected OPP client device */ class ObexServerRequestHandler extends ServerRequestHandler { /* * @see javax.obex.ServerRequestHandler#onConnect(HeaderSet, HeaderSet) */ public int onConnect(final HeaderSet request, final HeaderSet reply) { updateStatus("[SERVER] OPP session created"); return ResponseCodes.OBEX_HTTP_OK; } /** * @see javax.obex.ServerRequestHandler#onPut(Operation) */ public int onPut(final Operation op) { // Display information about the data received try { // Read the meta data of a received file final InputStream is = op.openInputStream(); updateStatus("[SERVER] File Name: " + op.getReceivedHeaders().getHeader(HeaderSet.NAME)); updateStatus("[SERVER] File Type: " + op.getType()); // Read the content of a received file final byte b[] = new byte[1024]; int len; updateStatus("[SERVER] File Content: "); while (is.available() > 0 && (len = is.read(b)) > 0) { updateStatus(new String(b, 0, len)); } } catch (final IOException ioe) { BluetoothJSR82Demo.errorDialog(ioe.toString()); } return ResponseCodes.OBEX_HTTP_OK; } /** * @see javax.obex.ServerRequestHandler#onDisconnect(HeaderSet, * HeaderSet) */ public void onDisconnect(final HeaderSet req, final HeaderSet resp) { updateStatus("[SERVER] OPP connection closed"); } } }