Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.moonlightcheese.btsrv;
- import java.lang.*;
- import java.lang.reflect.*;
- import java.io.*;
- import java.util.*;
- import android.app.*;
- import android.os.*;
- import android.bluetooth.*;
- import android.content.*;
- import android.util.Log;
- //service that dies when completely unbound
- public class ScannerService extends Service
- {
- //debugging
- private static final String LOG_TAG = "ScannerService";
- private static final boolean D = true;
- // Member fields
- public static final UUID BLUETOOTH_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //the UUID. magic.
- private final BluetoothAdapter mAdapter;
- private BluetoothDevice mDevice;
- private SharedPreferences mPrefs;
- private NotificationManager mNM;
- private AcceptThread mAcceptThread;
- private ConnectThread mConnectThread;
- private ConnectedThread mConnectedThread;
- private int mState;
- // valid states
- public static final String ACTION_START_SERVICE = "com.conceptualsystems.scannerservice.action.START_SERVICE";
- public static final String ACTION_STATE_CHANGED = "com.conceptualsystems.scannerservice.action.STATE_CHANGED";
- public static final String EXTRA_STATE = "com.conceptualsystems.scannerservice.extra.STATE";
- public static final String ACTION_SELECT_SCANNER = "com.conceptualsystems.scannerservice.action.SELECT_SCANNER";
- public static final String EXTRA_SELECTED_SCANNER = "com.conceptualsystems.scannerservice.extra.SELECTED_SCANNER";
- public static final String ACTION_READ_SCANNER = "com.conceptualsystems.scannerservice.action.READ_SCANNER";
- public static final String ACTION_REQUEST_RECONNECT = "com.conceptualsystems.scannerservice.action.REQUEST_RECONNECT";
- public static final String ACTION_RECONNECT = "com.conceptualsystems.scannerservice.action.RECONNECT";
- public static final String ACTION_RESET = "com.conceptualsystems.scannerservice.action.RESET";
- public static final String ACTION_REQUEST_STATE = "com.conceptualsystems.scannerservice.action.REQUEST_STATE";
- // Constants representing various notifications of this service
- public static final int NOTIFICATION_CONNECTION_CHANGED = 0;
- // Name for the SDP record when creating server socket
- private static final String NAME = "ScannerService";
- // Constants that indicate the current connection state
- public static final int STATE_NONE = 0; // we're doing nothing
- public static final int STATE_LISTEN = 1; // now listening for incoming connections
- public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
- public static final int STATE_CONNECTED = 3; // now connected to a remote device
- // Broadcast intent actions
- //public static final String
- //instance of the Binder we define in this Service
- private final IBinder mBinder = new ScannerBinder();
- // Class that extends Binder
- ////////////////////////////
- public class ScannerBinder extends Binder {
- ScannerService getService () {
- //return this instance
- return ScannerService.this;
- }
- }
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
- /**
- * Constructor. Prepares a new BluetoothChat session.
- * @param context The UI Activity Context
- * @param handler A Handler to send messages back to the UI Activity
- */
- public ScannerService() {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- //mState = STATE_NONE;
- //this.setState(STATE_NONE);
- }
- @Override
- public void onCreate() {
- this.setState(STATE_NONE);
- mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- // If the adapter is null, then Bluetooth is not supported
- showNotification("Service Started");
- mPrefs = getSharedPreferences("csccontrolcenterprefs", Context.MODE_PRIVATE);
- IntentFilter filter = new IntentFilter();
- filter.addAction(ScannerService.ACTION_STATE_CHANGED);
- filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
- filter.addAction(ScannerService.ACTION_SELECT_SCANNER);
- filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
- filter.addAction(ScannerService.ACTION_RESET);
- filter.addAction(ScannerService.ACTION_REQUEST_STATE);
- registerReceiver(mReceiver, filter);
- if (mAdapter == null) {
- // TODO: find a way to make the application exit here.
- // there is no reason to run this at all if there is no bluetooth adapter.
- //return;
- if(D) Log.e(LOG_TAG, "BAD THINGS HAPPENED: bluetooth adapter is null, so this device either doesn't have bluetooth, or the powers that be simply don't like you.");
- }
- // If BT is not on, request that it be enabled.
- // setupChat() will then be called during onActivityResult
- if (!mAdapter.isEnabled()) {
- mAdapter.enable();
- // Otherwise, setup the chat session
- } else {
- //bluetooth is already enabled, so start connection attempt
- this.start();
- }
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- unregisterReceiver(mReceiver);
- mNM.cancel(NOTIFICATION_CONNECTION_CHANGED);
- }
- /**
- * Set the current state of the chat connection
- * @param state An integer defining the current connection state
- */
- private synchronized void setState(int state) {
- if (D) Log.d(LOG_TAG, "setState() " + mState + " -> " + state);
- mState = state;
- Intent i = new Intent(ScannerService.ACTION_STATE_CHANGED);
- i.putExtra(ScannerService.EXTRA_STATE, mState);
- sendBroadcast(i);
- }
- /**
- * Return the current connection state.
- */
- public synchronized int getState() {
- return mState;
- }
- private void showNotification(String tickerText) {
- Notification notification = new Notification(R.drawable.icon, tickerText, System.currentTimeMillis());
- Intent selectionIntent = new Intent(this, SelectActivity.class);
- selectionIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0, selectionIntent, 0); //this is how we will launch an Activity when the user clicks the notification
- notification.setLatestEventInfo(this, getText(R.string.app_name), tickerText, contentIntent);
- notification.flags|=Notification.FLAG_ONGOING_EVENT;
- mNM.notify(NOTIFICATION_CONNECTION_CHANGED, notification); //send the notification to the system, to be displayed in the notification bar
- }
- // Create a BroadcastReceiver for ACTION_FOUND, ACTION_STATE_CHANGED, ACTION_DISCOVERY_FINISHED
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
- int state = mAdapter.getState();
- if(BluetoothAdapter.STATE_ON == state) {
- //bluetooth has been enabled. attempt to connect to a scanner now.
- ScannerService.this.stop(); //clear out the connection threads
- ScannerService.this.start(); //reinitialize
- }
- if(BluetoothAdapter.STATE_OFF == state) {
- //
- ScannerService.this.start();
- }
- }
- if(ScannerService.ACTION_REQUEST_STATE.equals(action)) {
- Intent i = new Intent(ScannerService.ACTION_STATE_CHANGED);
- i.putExtra(ScannerService.EXTRA_STATE, getState());
- context.sendBroadcast(i);
- }
- if(ScannerService.ACTION_SELECT_SCANNER.equals(action)) {
- String macAddress = intent.getStringExtra(ScannerService.EXTRA_SELECTED_SCANNER);
- if(D) Log.i(LOG_TAG, "got scanner selection: "+macAddress);
- SharedPreferences.Editor edit = mPrefs.edit();
- edit.putString("scanner", macAddress);
- edit.commit();
- ScannerService.this.start();
- }
- if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
- //ScannerService.this.start();
- }
- if(ScannerService.ACTION_RESET.equals(action)) {
- Log.i(LOG_TAG, "reset request received");
- if(mAdapter.isEnabled()) {
- //ScannerService.this.stop();
- //ScannerService.this.start();
- mAdapter.disable();
- } else {
- ScannerService.this.start();
- }
- }
- }
- };
- /**
- * Start the chat service. Specifically start AcceptThread to begin a
- * session in listening (server) mode. Called by the Activity onResume() */
- public synchronized void start() {
- if (D) Log.d(LOG_TAG, "start");
- if (!mAdapter.isEnabled()) {
- mAdapter.enable();
- return;
- }
- // Cancel any thread attempting to make a connection
- if (mState == STATE_CONNECTING) {
- if (mConnectThread != null) {
- //mConnectThread.cancel(); //this fails because the Thread dies after connection, but is not null. we can't call .cancel() if the Thread isn't running.
- mConnectThread = null;
- }
- }
- // Cancel any thread currently running a connection
- if (mConnectedThread != null) {
- mConnectedThread.cancel(); //this doesn't fail only because we know that if the Thread exists, it is looping and running. this seems like bad coding, but don't know how to fix it. was part of the Android example.
- mConnectedThread = null;
- }
- /*** OLD GARBAGE FROM BTCHATEXAMPLE ***
- // Start the thread to listen on a BluetoothServerSocket
- if (mAcceptThread == null) {
- mAcceptThread = new AcceptThread();
- mAcceptThread.start();
- }
- */
- //setState(STATE_LISTEN);
- //check if we have set a preference for our scanner
- //if not, display the selection dialog.
- if(mPrefs!=null && mPrefs.contains("scanner")) {
- try {
- mDevice = mAdapter.getRemoteDevice(mPrefs.getString("scanner", null));
- } catch(Exception e) {
- if(D) Log.e(LOG_TAG, "i dunno how in the world you did it, but somehow you stored a null MAC address when selecting a scanner");
- }
- if(mDevice!=null) {
- this.connect(mDevice);
- } else {
- if(D) Log.e(LOG_TAG, "mDevice is somehow null, after calling getRemoteDevice");
- }
- } else {
- //start the activity that allows the user to set the bluetooth scanner
- if(D) Log.i(LOG_TAG, "either mPrefs was null (which is really bad) or you need to select a scanner (not so bad)");
- ////////////////////////////////////////////////////
- // TODO: start the scanner selection activity here
- ////////////////////////////////////////////////////
- Intent i = new Intent(ScannerService.this, SelectActivity.class);
- i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(i);
- }
- }
- /**
- * Stop all threads
- */
- public synchronized void stop() {
- if (D) Log.d(LOG_TAG, "stop");
- if (mConnectThread != null) {
- //mConnectThread.cancel();
- mConnectThread = null;
- }
- Log.i(LOG_TAG, "ended connect thread");
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
- Log.i(LOG_TAG, "ended connected thread");
- if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
- setState(STATE_NONE);
- }
- public synchronized void nullify(Thread t) {
- t=null;
- }
- /**
- * Start the ConnectThread to initiate a connection to a remote device.
- * @param device The BluetoothDevice to connect
- */
- public synchronized void connect(BluetoothDevice device) {
- if (D) Log.d(LOG_TAG, "connect to: " + device);
- // Cancel any thread attempting to make a connection
- if (mState == STATE_CONNECTING) {
- if (mConnectThread != null) {
- //mConnectThread.cancel(); //this should actually work without a hitch, solving the problem presented in the comments above in start()
- mConnectThread = null;
- }
- }
- // Cancel any thread currently running a connection
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
- // Start the thread to connect with the given device
- mConnectThread = new ConnectThread(device);
- mConnectThread.start();
- setState(STATE_CONNECTING);
- }
- /**
- * Start the ConnectedThread to begin managing a Bluetooth connection
- * @param socket The BluetoothSocket on which the connection was made
- * @param device The BluetoothDevice that has been connected
- */
- public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
- if (D) Log.d(LOG_TAG, "connected");
- // Cancel any thread currently running a connection
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
- // Start the thread to manage the connection and perform transmissions
- mConnectedThread = new ConnectedThread(socket);
- mConnectedThread.start();
- // Cancel the accept thread because we only want to connect to one device
- if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
- // Cancel the thread that completed the connection
- if (mConnectThread != null) {
- //mConnectThread.cancel();
- mConnectThread = null;
- }
- // update the notification bar and let the user know we are connected.
- showNotification("Scanner Connected");
- // Send the name of the connected device back to the UI Activity
- // TODO: there is nothing to change here. we don't care what the name is once we're connected.
- // just leave this commented.
- /***
- Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);
- Bundle bundle = new Bundle();
- bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());
- msg.setData(bundle);
- mHandler.sendMessage(msg);
- ***/
- setState(STATE_CONNECTED);
- }
- /**
- * Indicate that the connection attempt failed and notify the UI Activity.
- */
- private void connectionFailed() {
- setState(STATE_NONE);
- // Send a failure message to notification bar
- showNotification("Scanner Disconnected");
- Log.e(LOG_TAG, "connectionFailed()");
- ///////DEPRECATED: we now inform the user that the connection failed and prompt them to try again.
- // after we send a failure message, automatically attempt to reconnect
- //this.start();
- //Intent intentError = new Intent(ScannerService.this, ErrorActivity.class);
- //intentError.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- //startActivity(intentError);
- /***
- Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
- Bundle bundle = new Bundle();
- bundle.putString(BluetoothChat.TOAST, "Unable to connect device");
- msg.setData(bundle);
- mHandler.sendMessage(msg);
- ***/
- }
- /**
- * Indicate that the connection was lost and notify the UI Activity.
- */
- private void connectionLost() {
- setState(STATE_NONE);
- // Send a failure message to notification bar
- showNotification("Scanner Disconnected");
- Log.e(LOG_TAG, "connectionLost()");
- ///////DEPRECATED: we now inform the user that the connection failed and prompt them to try again.
- // after we send a failure message, automatically attempt to reconnect
- //this.start();
- //Intent intentError = new Intent(ScannerService.this, ErrorActivity.class);
- //intentError.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- //startActivity(intentError);
- /**
- Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
- Bundle bundle = new Bundle();
- bundle.putString(BluetoothChat.TOAST, "Device connection was lost");
- msg.setData(bundle);
- mHandler.sendMessage(msg);
- **/
- }
- /**
- * This thread runs while listening for incoming connections. It behaves
- * like a server-side client. It runs until a connection is accepted
- * (or until cancelled).
- */
- private class AcceptThread extends Thread {
- // The local server socket
- private final BluetoothServerSocket mmServerSocket;
- public AcceptThread() {
- BluetoothServerSocket tmp = null;
- // Create a new listening server socket
- try {
- tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, BLUETOOTH_UUID);
- } catch (IOException e) {
- Log.e(LOG_TAG, "listen() failed", e);
- mAdapter.disable();
- }
- mmServerSocket = tmp;
- }
- public void run() {
- if (D) Log.d(LOG_TAG, "BEGIN mAcceptThread" + this);
- setName("AcceptThread");
- BluetoothSocket socket = null;
- // Listen to the server socket if we're not connected
- while (mState != STATE_CONNECTED) {
- try {
- // This is a blocking call and will only return on a
- // successful connection or an exception
- socket = mmServerSocket.accept();
- } catch (IOException e) {
- Log.e(LOG_TAG, "accept() failed", e);
- break;
- }
- // If a connection was accepted
- if (socket != null) {
- synchronized (ScannerService.this) {
- switch (mState) {
- case STATE_LISTEN:
- case STATE_CONNECTING:
- // Situation normal. Start the connected thread.
- connected(socket, socket.getRemoteDevice());
- break;
- case STATE_NONE:
- case STATE_CONNECTED:
- // Either not ready or already connected. Terminate new socket.
- try {
- socket.close();
- } catch (IOException e) {
- Log.e(LOG_TAG, "Could not close unwanted socket", e);
- }
- break;
- }
- }
- }
- }
- if (D) Log.i(LOG_TAG, "END mAcceptThread");
- }
- public void cancel() {
- if (D) Log.d(LOG_TAG, "cancel " + this);
- try {
- mmServerSocket.close();
- } catch (IOException e) {
- Log.e(LOG_TAG, "close() of server failed", e);
- }
- }
- }
- /**
- * This thread runs while attempting to make an outgoing connection
- * with a device. It runs straight through; the connection either
- * succeeds or fails.
- */
- private class ConnectThread extends Thread {
- private final BluetoothSocket mmSocket;
- private final BluetoothDevice mmDevice;
- public ConnectThread(BluetoothDevice device) {
- mmDevice = device;
- BluetoothSocket tmp = null;
- // Get a BluetoothSocket for a connection with the
- // given BluetoothDevice
- try {
- //tmp = device.createRfcommSocketToServiceRecord(BLUETOOTH_UUID);
- Method m = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
- tmp = (BluetoothSocket)m.invoke(device, Integer.valueOf(1));
- } catch (Exception e) {
- Log.e(LOG_TAG, "create() failed", e);
- connectionFailed();
- /*
- if(mAdapter.isEnabled()) {
- mAdapter.disable();
- } else {
- ScannerService.this.start();
- }
- */
- }
- mmSocket = tmp;
- }
- public void run() {
- if(mmSocket!=null) {
- Log.i(LOG_TAG, "BEGIN mConnectThread");
- setName("ConnectThread");
- // Always cancel discovery because it will slow down a connection
- mAdapter.cancelDiscovery();
- // Make a connection to the BluetoothSocket
- try {
- // This is a blocking call and will only return on a
- // successful connection or an exception
- mmSocket.connect();
- } catch (IOException e) {
- Log.e(LOG_TAG, "unable to connect() socket IOEXCEPTION", e);
- connectionFailed();
- // Close the socket
- try {
- mmSocket.close();
- } catch (IOException e2) {
- Log.e(LOG_TAG, "unable to close() socket during connection failure", e2);
- }
- return;
- } catch (NullPointerException e1) {
- Log.e(LOG_TAG, "unable to connect() socket NULLPOINTEREXCEPTION", e1);
- mAdapter.disable();
- return;
- }
- // Reset the ConnectThread because we're done
- //synchronized (ScannerService.this) {
- // mConnectThread = null;
- //}
- // Start the connected thread
- if(mmSocket!=null && mmDevice!=null) {
- connected(mmSocket, mmDevice);
- }
- try {
- Thread.sleep(1000);
- } catch(Exception e) {
- Log.e(LOG_TAG, "couldn't wait, sorry brofus");
- }
- }
- }
- public void cancel() {
- try {
- mmSocket.close();
- } catch (IOException e) {
- Log.e(LOG_TAG, "close() of connect socket failed", e);
- } catch (NullPointerException e1) {
- Log.e(LOG_TAG, "unable to close() socket NULLPOINTEREXCEPTION", e1);
- }
- }
- }
- /**
- * This thread runs during a connection with a remote device.
- * It handles all incoming and outgoing transmissions.
- */
- private class ConnectedThread extends Thread {
- private final BluetoothSocket mmSocket;
- private final LineNumberReader mmInStream;
- private final OutputStream mmOutStream;
- public ConnectedThread(BluetoothSocket socket) {
- Log.d(LOG_TAG, "create ConnectedThread");
- mmSocket = socket;
- LineNumberReader tmpIn = null;
- OutputStream tmpOut = null;
- // Get the BluetoothSocket input and output streams
- try {
- tmpIn = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
- tmpOut = socket.getOutputStream();
- } catch (IOException e) {
- Log.e(LOG_TAG, "temp sockets not created", e);
- }
- mmInStream = tmpIn;
- mmOutStream = tmpOut;
- }
- public void run() {
- Log.i(LOG_TAG, "BEGIN mConnectedThread");
- while(true) {
- try {
- String curScan = mmInStream.readLine();
- if (D) Log.i(LOG_TAG, "scan read in service: "+curScan);
- //////////////////////////////////////////////
- //TODO: send the read intent from here
- //////////////////////////////////////////////
- Intent i = new Intent(ScannerService.ACTION_READ_SCANNER);
- i.putExtra("scannerRead", curScan);
- sendBroadcast(i);
- } catch(IOException e) {
- connectionLost();
- break;
- }
- }
- }
- public void cancel() {
- try {
- mmSocket.close();
- } catch (IOException e) {
- Log.e(LOG_TAG, "close() of connect socket failed", e);
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement