Advertisement
moonlightcheese

Untitled

Jul 6th, 2011
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 16.07 KB | None | 0 0
  1. package com.moonlightcheese.btsrv;
  2.  
  3. import java.lang.*;
  4. import java.io.*;
  5. import java.util.*;
  6.  
  7. import android.app.*;
  8. import android.os.*;
  9. import android.bluetooth.*;
  10. import android.content.*;
  11. import android.util.Log;
  12.  
  13. //service that dies when completely unbound
  14. public class ScannerService extends Service
  15. {  
  16.     //instance of the Binder we define in this Service
  17.     private final IBinder mBinder = new ScannerBinder();
  18.    
  19.     //local variable needed for bluetooth connectivity
  20.     BluetoothAdapter btAdapter;         //the local Bluetooth adapter
  21.     BluetoothDevice mScanner;           //the scanner we are connecting to
  22.     boolean isDiscoveringLocal = false; //a boolean value that we set/unset to tell if this service initiated discovery, this avoids listing devices if another application initiated the discovery
  23.     List<BluetoothDevice> scannerList;  //the list of bluetooth scanners found during discovery
  24.     public static final UUID BLUETOOTH_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");      //the UUID.  magic.
  25.     ReconnectThread mRCT;
  26.     BluetoothConnectThread mBCT;
  27.     SharedPreferences mPrefs;
  28.    
  29.     //message ids and constants
  30.     public final static int MESSAGE_BT_READ = 21;
  31.     public final static int MESSAGE_SOCKET_ERROR = 22;
  32.     public final static int REQUEST_ENABLE_BT = 10;
  33.     public final static String ACTION_SELECT_SCANNER = "com.conceptualsystems.scannerservice.selectscanner";
  34.     public final static String ACTION_READ_SCANNER = "com.conceptualsystems.scannerservice.readscanner";
  35.     public final static String ACTION_REQUEST_RECONNECT = "com.conceptualsystems.scannerservice.request_reconnect";
  36.     public final static String ACTION_RECONNECT = "com.conceptualsystems.scannerservice.reconnect";
  37.     public final static String LOG_TAG = "btsrv - ScannerService.java";
  38.    
  39.     // Class that extends Binder
  40.     ////////////////////////////
  41.     public class ScannerBinder extends Binder {
  42.         ScannerService getService () {
  43.             //return this instance
  44.             return ScannerService.this;
  45.         }
  46.     }
  47.    
  48.     @Override
  49.     public IBinder onBind(Intent intent) {
  50.         return mBinder;
  51.     }
  52.    
  53.     @Override
  54.     public void onCreate()
  55.     {
  56.         super.onCreate();
  57.        
  58.         scannerList = new ArrayList<BluetoothDevice>();
  59.         mPrefs = getSharedPreferences("conceptualbluetoothscannerpreferences", Context.MODE_PRIVATE);
  60.        
  61.         // Register the BroadcastReceiver
  62.         IntentFilter filter = new IntentFilter();
  63.         filter.addAction(BluetoothDevice.ACTION_FOUND);
  64.         filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
  65.         filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
  66.         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
  67.         filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
  68.         filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
  69.         filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
  70.         filter.addAction(ScannerService.ACTION_RECONNECT);
  71.         //TODO: unregister receiver onDestroy()
  72.         registerReceiver(mReceiver, filter);
  73.     }
  74.    
  75.     @Override
  76.     public void onDestroy() {
  77.         super.onDestroy();
  78.         if(mRCT!=null && mRCT.mReconnecting) {
  79.             Log.i(LOG_TAG, "attempting reconnect...");
  80.             mRCT.interrupt();
  81.         }
  82.         Log.i(LOG_TAG, "onDestroy called in ScannerService");
  83.         unregisterReceiver(mReceiver);
  84.         if(mBCT!=null) {
  85.             Log.i(LOG_TAG, "killing mBCT");
  86.             //mBCT.cancel();
  87.         }
  88.     }
  89.    
  90.     private class ReconnectThread extends Thread {
  91.         //Members
  92.         BluetoothDevice mDevice;
  93.         public boolean mReconnecting;
  94.        
  95.         //Constructor
  96.         public ReconnectThread(BluetoothDevice device) {
  97.             this.mDevice=device;
  98.             this.mReconnecting=true;
  99.         }
  100.        
  101.         public void reconnect() {
  102.             try {
  103.                 this.mReconnecting=true;
  104.                 mBCT = new BluetoothConnectThread(mScanner, btHandler);
  105.                 mBCT.start();
  106.             } catch(Exception e) {
  107.                 if(mScanner==null) {
  108.                     Log.i(LOG_TAG, "mScanner: error in RCT: "+e.getMessage());
  109.                 }
  110.                 if(btHandler==null) {
  111.                     Log.i(LOG_TAG, "btHandler: error in RCT: "+e.getMessage());
  112.                 }
  113.                 if(mBCT==null) {
  114.                     Log.i(LOG_TAG, "mBCT: error in RCT: "+e.getMessage());
  115.                 }
  116.             }
  117.            
  118.         }
  119.        
  120.         public void run() {
  121.             //try to reconnect one time
  122.             this.reconnect();
  123.             //loop until an interrupt has been received
  124.             while(true) {
  125.                 try {
  126.                     Thread.sleep(1000);
  127.                 } catch(InterruptedException e) {
  128.                     this.mReconnecting=false;
  129.                     return;
  130.                 }
  131.             }
  132.         }
  133.     }
  134.    
  135.     // Create a BroadcastReceiver for ACTION_FOUND, ACTION_STATE_CHANGED, ACTION_DISCOVERY_FINISHED
  136.     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
  137.         public void onReceive(Context context, Intent intent) {
  138.             String action = intent.getAction();
  139.             if (BluetoothDevice.ACTION_FOUND.equals(action) && isDiscoveringLocal) {
  140.                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  141.                 boolean newEntry = true;
  142.                 Log.i(LOG_TAG, "found device: "+device.getName());
  143.                 for(BluetoothDevice storedDevice : scannerList) {
  144.                     if(device.getAddress().equals(storedDevice.getAddress())) {
  145.                         newEntry = false;
  146.                     }
  147.                 }
  148.                 if(newEntry) {
  149.                     scannerList.add(device);
  150.                 }
  151.             }
  152.             if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
  153.                 isDiscoveringLocal = false;
  154.                 Log.i(LOG_TAG, "discovery finished.");
  155.                 //TODO: broadcast an intent to interested applications so they can choose the device to use
  156.                 if(!scannerList.isEmpty()) {
  157.                     Intent i = new Intent(ACTION_SELECT_SCANNER);
  158.                     List<String> scannerLabels = new ArrayList<String>(scannerList.size());
  159.                     for(BluetoothDevice device : scannerList) {
  160.                         scannerLabels.add(device.getName()+"\n"+device.getBluetoothClass().toString());
  161.                     }
  162.                     i.putExtra("scannerArray", scannerLabels.toArray(new String[1]));
  163.                     sendBroadcast(i);
  164.                     Log.i(LOG_TAG, "sent broadcast with array elements: " + scannerList.toString());
  165.                     Log.i(LOG_TAG, "size of scannerList: " + scannerList.size());
  166.                     Log.i(LOG_TAG, "size of scannerLabels: " + scannerLabels.size());
  167.                 } else {
  168.                     Intent i = new Intent(ACTION_SELECT_SCANNER);
  169.                     sendBroadcast(i);
  170.                     Log.i(LOG_TAG, "sent broadcast with empty intent (no extras)");
  171.                 }
  172.             }
  173.             if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
  174.                 if(BluetoothAdapter.STATE_ON == btAdapter.getState()) {
  175.                     //initialize();     //make a call to initialize when the adapter turns on to perform the discovery process
  176.                 }
  177.             }
  178.             ////////////////////////////
  179.             //TODO: may need to rebond sometimes.  initiate rebonding if device becomes unpaired here.
  180.             if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
  181.                 int bondState = -1;
  182.                 int oldBondState = -1;
  183.                 BluetoothDevice device = null;
  184.                 try {
  185.                     bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
  186.                     oldBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.BOND_NONE);
  187.                     device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  188.                 } catch (Exception e) {
  189.                     //
  190.                 }
  191.                 Log.i(LOG_TAG, "bond state changed.");
  192.                 Log.i(LOG_TAG, "device name: "+device.getName());
  193.                 Log.i(LOG_TAG, "device addr: "+device.getAddress());
  194.                 switch(bondState) {
  195.                     case BluetoothDevice.BOND_NONE:
  196.                         Log.i(LOG_TAG, "now unbonded");
  197.                         break;
  198.                     case BluetoothDevice.BOND_BONDED:
  199.                         Log.i(LOG_TAG, "now bonded");
  200.                         break;
  201.                     case BluetoothDevice.BOND_BONDING:
  202.                         Log.i(LOG_TAG, "now bonding");
  203.                         break;
  204.                 }
  205.                 switch(oldBondState) {
  206.                     case BluetoothDevice.BOND_NONE:
  207.                         Log.i(LOG_TAG, "was unbonded");
  208.                         break;
  209.                     case BluetoothDevice.BOND_BONDED:
  210.                         Log.i(LOG_TAG, "was bonded");
  211.                         break;
  212.                     case BluetoothDevice.BOND_BONDING:
  213.                         Log.i(LOG_TAG, "was bonding");
  214.                         break;
  215.                 }
  216.             }
  217.             if(BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
  218.                 Log.i(LOG_TAG, "connected.");
  219.                 if(mScanner!=null) {
  220.                     SharedPreferences myPrefs = context.getSharedPreferences("conceptualbluetoothscannerpreferences", Context.MODE_PRIVATE);
  221.                     SharedPreferences.Editor editor = myPrefs.edit();
  222.                     editor.putString("lastscanner", mScanner.getAddress());
  223.                     editor.commit();
  224.                 }
  225.                 if(mRCT!=null && mRCT.mReconnecting) {
  226.                     mRCT.interrupt();
  227.                 }
  228.             }
  229.             if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
  230.                 Log.i(LOG_TAG, "disconnected.");
  231.                 //TODO: check the pref stored device in addition to the local, last used device in memory
  232.                 Intent reconnectIntent = new Intent();
  233.                 reconnectIntent.setAction(ScannerService.ACTION_REQUEST_RECONNECT);
  234.                 sendBroadcast(reconnectIntent);
  235.             }
  236.             if(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {
  237.                 Log.i(LOG_TAG, "disconnect requested.");
  238.             }
  239.             if(ScannerService.ACTION_RECONNECT.equals(action)) {
  240.                 if(mScanner!=null) {
  241.                     mRCT = new ReconnectThread(mScanner);
  242.                     mRCT.start();
  243.                 }
  244.             }
  245.         }
  246.     };
  247.    
  248.     public void selectBluetoothDevice(int selection) {
  249.         //
  250.         if(scannerList.isEmpty()) {
  251.             //TODO: NullPointerException needs to go here
  252.             Log.i(LOG_TAG, "NullPointerException?");
  253.         } else {
  254.             if(selection > scannerList.size()-1 || selection < 0) {
  255.                 //TODO: IllegalArgumentException needs to go here
  256.                 Log.i(LOG_TAG, "IllegalArgumentException");
  257.             } else {
  258.                 //argument should be good, use this selection to select the BluetoothDevice to connect to
  259.                 mScanner = scannerList.get(selection);
  260.                 scannerList.clear(); //clear the list after selection
  261.                 mBCT = new BluetoothConnectThread(mScanner, btHandler);
  262.                 mBCT.start();
  263.             }
  264.         }
  265.     }
  266.    
  267.     public void startBluetoothDiscovery() {
  268.         isDiscoveringLocal = true;
  269.         Log.i(LOG_TAG, "starting discovery process...");
  270.         btAdapter.startDiscovery();
  271.     }
  272.    
  273.     public void connectLastScanner() {
  274.         String scannerAddress = mPrefs.getString("lastscanner", null);
  275.         if(scannerAddress!=null) {
  276.             mScanner = btAdapter.getRemoteDevice(scannerAddress);
  277.             Log.i(LOG_TAG, "connecting to last known scanner: "+mScanner.getAddress());
  278.             mBCT = new BluetoothConnectThread(mScanner, btHandler);
  279.             mBCT.start();
  280.         }
  281.     }
  282.    
  283.     public boolean initialize() {
  284.         btAdapter = BluetoothAdapter.getDefaultAdapter();
  285.         if(btAdapter == null) {
  286.             //no bluetooth adapter available.  do not run bluetooth code.
  287.             return false;
  288.         } else {
  289.             if(!btAdapter.isEnabled()) {  //enable bluetooth if disabled.
  290.                 btAdapter.enable();
  291.                 scannerList.clear();
  292.             } else {
  293.                 scannerList.clear();
  294.             }
  295.         }
  296.         while(!btAdapter.isEnabled());
  297.         return true;
  298.     }
  299.    
  300.     public boolean disable() {
  301.         btAdapter = BluetoothAdapter.getDefaultAdapter();
  302.         if(btAdapter!=null) {
  303.             btAdapter.disable();
  304.             mScanner = null;
  305.             scannerList.clear();
  306.         } else {
  307.             return false;
  308.         }
  309.         return true;
  310.     }
  311.    
  312.     public boolean isBonded(BluetoothDevice device) {
  313.         if(device.getBondState()==BluetoothDevice.BOND_NONE) {
  314.             return false;
  315.         }
  316.        
  317.         return true;
  318.     }
  319.     /*
  320.     public boolean doBond(BluetoothDevice device) {
  321.         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
  322.         intent.putExtra(EXTRA_DEVICE, device);
  323.         int PAIRING_VARIANT_PIN = 272;
  324.         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);
  325.         sendBroadcast(intent);
  326.     }
  327.     */
  328.     private class BluetoothServerThread extends Thread {
  329.         private BluetoothServerSocket btServerSocket;
  330.        
  331.         public BluetoothServerThread() {
  332.             BluetoothServerSocket tmp = null;
  333.             try {
  334.                 tmp = btAdapter.listenUsingRfcommWithServiceRecord("smsmobile", BLUETOOTH_UUID);
  335.             } catch (IOException e) {}
  336.             btServerSocket = tmp;
  337.         }
  338.        
  339.         public void run() {
  340.             BluetoothSocket socket = null;
  341.             while(true) {
  342.                 try {
  343.                     socket = btServerSocket.accept();
  344.                 } catch (IOException e) {
  345.                     break;
  346.                 }
  347.                 if(socket != null) {
  348.                     BluetoothSocketThread socketThread = new BluetoothSocketThread(socket, btHandler);
  349.                     socketThread.start();
  350.                     try {
  351.                         btServerSocket.close();
  352.                     } catch (IOException e) {
  353.                         Log.e(LOG_TAG+":bst", "could not close the server socket?  i mean srsly, wtf?");
  354.                     }
  355.                     break;
  356.                 }
  357.             }
  358.         }
  359.        
  360.         public void cancel() {
  361.             try {
  362.                 btServerSocket.close();
  363.             } catch (IOException e) {}
  364.         }
  365.     };
  366.    
  367.     private class BluetoothConnectThread extends Thread {
  368.         private BluetoothSocket mSocket;
  369.         private BluetoothDevice mDevice;
  370.         private Handler mHandler;
  371.         private BluetoothSocketThread mBST;
  372.        
  373.         public BluetoothConnectThread(BluetoothDevice device, Handler handler) {
  374.             BluetoothSocket tmp = null;
  375.             mDevice = device;
  376.             mHandler = handler;
  377.            
  378.             try {
  379.                 tmp = device.createRfcommSocketToServiceRecord(BLUETOOTH_UUID);
  380.             } catch (IOException e) {
  381.                 Log.e(LOG_TAG, "could not create rfcomm socket as client");
  382.             }
  383.            
  384.             mSocket = tmp;
  385.         }
  386.        
  387.         public synchronized void run() {
  388.             btAdapter.cancelDiscovery();
  389.             try {
  390.                 mSocket.connect();
  391.                 mBST = new BluetoothSocketThread(mSocket, btHandler);
  392.                 mBST.start();
  393.             } catch (Exception e) {
  394.                 if(mSocket == null) {
  395.                     Log.e(LOG_TAG, "device socket was never initiated, socket is null");
  396.                 }
  397.                 Log.e(LOG_TAG, "connection failed");
  398.                 Log.e(LOG_TAG, e.toString());
  399.                 Message m = Message.obtain(mHandler, MESSAGE_SOCKET_ERROR);
  400.                 mHandler.sendMessage(m);
  401.             }
  402.         }
  403.        
  404.         public void cancel() {
  405.             mBST.cancel();
  406.         }
  407.     };
  408.    
  409.     private class BluetoothSocketThread extends Thread {
  410.         private BluetoothSocket mSocket;
  411.         private LineNumberReader mInStream;
  412.         private OutputStream mOutStream;
  413.         private Handler mHandler;
  414.        
  415.         public BluetoothSocketThread(BluetoothSocket socket, Handler handler) {
  416.             mSocket = socket;
  417.             LineNumberReader tmpIn = null;
  418.             OutputStream tmpOut = null;
  419.             mHandler = handler;
  420.            
  421.             try {
  422.                 tmpIn = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
  423.                 tmpOut = socket.getOutputStream();
  424.             } catch(IOException e) {
  425.                 Log.e(LOG_TAG, "could not capture input/output stream");
  426.                 //Message m = Message.obtain(mHandler, MESSAGE_SOCKET_ERROR);
  427.                 //mHandler.sendMessage(m);
  428.             }
  429.            
  430.             mInStream = tmpIn;
  431.             mOutStream = tmpOut;
  432.         }
  433.        
  434.         public void run() {
  435.             //Message m = Message.obtain(mHandler, MESSAGE_SOCKET_SEND, mSocket);
  436.             //mHandler.sendMessage(m);
  437.             Log.i(LOG_TAG, "socket successfully connected... starting listener loop");
  438.             while(true) {
  439.                 try {
  440.                     String curScan = mInStream.readLine();
  441.                     Log.i(LOG_TAG, "scan read in service: "+curScan);
  442.                     Message m = Message.obtain(mHandler, MESSAGE_BT_READ, curScan);
  443.                     mHandler.sendMessage(m);
  444.                 } catch(IOException e) {
  445.                     Log.e(LOG_TAG, "read or handling error, dropping connection");
  446.                     this.cancel();
  447.                     break;
  448.                 }
  449.             }
  450.         }
  451.        
  452.         public void write(byte[] bytes) {
  453.             try {
  454.                 mOutStream.write(bytes);
  455.             } catch (IOException e) {
  456.                 Log.e(LOG_TAG, "write error");
  457.             }
  458.         }
  459.        
  460.         public void cancel() {
  461.             try {
  462.                 mInStream.close();
  463.                 mOutStream.close();
  464.                 mSocket.close();
  465.                 mInStream = null;
  466.                 mOutStream = null;
  467.                 mSocket = null;
  468.             } catch(IOException e) {
  469.                 Log.i(LOG_TAG, "client connection wouldn't close");
  470.             }
  471.         }
  472.     };
  473.    
  474.     private final Handler btHandler = new Handler() {
  475.         @Override
  476.         public void handleMessage(Message msg) {
  477.             switch(msg.what) {
  478.                 case MESSAGE_BT_READ:
  479.                     //a read was requested
  480.                     ////broadcast an intent containing the string read from the scanner
  481.                     Intent i = new Intent(ACTION_READ_SCANNER);
  482.                     i.putExtra("scannerRead", (String)msg.obj);
  483.                     sendBroadcast(i);
  484.                     //Log.i(LOG_TAG+":bth", "read a message" + (String)msg.obj);
  485.                     break;
  486.                 case MESSAGE_SOCKET_ERROR:
  487.                     //error.  if the reconnect thread is up and running, attempt a reconnect.
  488.                     Log.e(LOG_TAG, "a socket error occurred when trying to connect");
  489.                     if(mRCT!=null && mRCT.mReconnecting) {
  490.                         Log.i(LOG_TAG, "attempting reconnect...");
  491.                         mRCT.reconnect();
  492.                     } else {
  493.                         //this was a first attempt.  what do?
  494.                         //first let's try to disconnect manually since the device may think it's connected to something.
  495.                         if(mScanner!=null && !isBonded(mScanner)) {
  496.                             //bond the scanner (pairing)
  497.                             //doBond(mScanner);
  498.                         } else {
  499.                             Log.e(LOG_TAG, "big problem, we got a socket error and mScanner was null.  that should pretty much never happen.  ever.");
  500.                         }
  501.                     }
  502.                     break;
  503.             }
  504.         }
  505.     };
  506. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement