diff --git a/README.md b/README.md index 69a1891a..c2d6a246 100644 --- a/README.md +++ b/README.md @@ -1,731 +1,743 @@ -# Bluetooth Serial Plugin for PhoneGap - -This plugin enables serial communication over Bluetooth. It was written for communicating between Android or iOS and an Arduino. - -Android and Windows Phone use Classic Bluetooth. iOS uses Bluetooth Low Energy. - -## Supported Platforms - -* Android -* iOS with [RedBearLab](http://redbearlab.com) BLE hardware, [Adafruit Bluefruit LE](http://www.adafruit.com/products/1697), [Laird BL600](http://www.lairdtech.com/Products/Embedded-Wireless-Solutions/Bluetooth-Radio-Modules/BL600-Series/#.VBI7AS5dUzI), or [BlueGiga](https://bluegiga.zendesk.com/entries/29185293--BGScript-spp-over-ble-AT-command-SPP-implementation-for-BLE) -* Windows Phone 8 -* Browser (Testing only. See [comments](https://github.com/don/BluetoothSerial/blob/master/src/browser/bluetoothSerial.js).) - -[Supporting other Bluetooth Low Energy hardware](#supporting-other-ble-hardware) - -## Limitations - - * The phone must initiate the Bluetooth connection - * iOS Bluetooth Low Energy requires iPhone 4S, iPhone5, iPod 5, or iPad3+ - * Will *not* connect Android to Android[*](https://github.com/don/BluetoothSerial/issues/50#issuecomment-66405396) - * Will *not* connect iOS to iOS[*](https://github.com/don/BluetoothSerial/issues/75#issuecomment-52591397) - -# Installing - -Install with Cordova cli - - $ cordova plugin add cordova-plugin-bluetooth-serial - -Note that this plugin's id changed from `com.megster.cordova.bluetoothserial` to `cordova-plugin-bluetooth-serial` as part of the migration from the [Cordova plugin repo](http://plugins.cordova.io/) to [npm](https://www.npmjs.com/). - -# Examples - -There are some [sample projects](https://github.com/don/BluetoothSerial/tree/master/examples) included with the plugin. - -# API - -## Methods - -- [bluetoothSerial.connect](#connect) -- [bluetoothSerial.connectInsecure](#connectInsecure) -- [bluetoothSerial.disconnect](#disconnect) -- [bluetoothSerial.write](#write) -- [bluetoothSerial.available](#available) -- [bluetoothSerial.read](#read) -- [bluetoothSerial.readUntil](#readuntil) -- [bluetoothSerial.subscribe](#subscribe) -- [bluetoothSerial.unsubscribe](#unsubscribe) -- [bluetoothSerial.subscribeRawData](#subscriberawdata) -- [bluetoothSerial.unsubscribeRawData](#unsubscriberawdata) -- [bluetoothSerial.clear](#clear) -- [bluetoothSerial.list](#list) -- [bluetoothSerial.isEnabled](#isenabled) -- [bluetoothSerial.isConnected](#isconnected) -- [bluetoothSerial.readRSSI](#readrssi) -- [bluetoothSerial.showBluetoothSettings](#showbluetoothsettings) -- [bluetoothSerial.enable](#enable) -- [bluetoothSerial.discoverUnpaired](#discoverunpaired) -- [bluetoothSerial.setDeviceDiscoveredListener](#setdevicediscoveredlistener) -- [bluetoothSerial.clearDeviceDiscoveredListener](#cleardevicediscoveredlistener) -- [bluetoothSerial.setName](#setname) -- [bluetoothSerial.setDiscoverable](#setdiscoverable) - -## connect - -Connect to a Bluetooth device. - - bluetoothSerial.connect(macAddress_or_uuid, connectSuccess, connectFailure); - -### Description - -Function `connect` connects to a Bluetooth device. The callback is long running. Success will be called when the connection is successful. Failure is called if the connection fails, or later if the connection disconnects. An error message is passed to the failure callback. - -#### Android -For Android, `connect` takes a MAC address of the remote device. - -#### iOS -For iOS, `connect` takes the UUID of the remote device. Optionally, you can pass an **empty string** and the plugin will connect to the first BLE peripheral. - -#### Windows Phone -For Windows Phone, `connect` takes a MAC address of the remote device. The MAC address can optionally surrounded with parenthesis. e.g. `(AA:BB:CC:DD:EE:FF)` - - -### Parameters - -- __macAddress_or_uuid__: Identifier of the remote device. -- __connectSuccess__: Success callback function that is invoked when the connection is successful. -- __connectFailure__: Error callback function, invoked when error occurs or the connection disconnects. - -## connectInsecure - -Connect insecurely to a Bluetooth device. - - bluetoothSerial.connectInsecure(macAddress, connectSuccess, connectFailure); - -### Description - -Function `connectInsecure` works like [connect](#connect), but creates an insecure connection to a Bluetooth device. See the [Android docs](http://goo.gl/1mFjZY) for more information. - -#### Android -For Android, `connectInsecure` takes a macAddress of the remote device. - -#### iOS -`connectInsecure` is **not supported** on iOS. - -#### Windows Phone -`connectInsecure` is **not supported** on Windows Phone. - -### Parameters - -- __macAddress__: Identifier of the remote device. -- __connectSuccess__: Success callback function that is invoked when the connection is successful. -- __connectFailure__: Error callback function, invoked when error occurs or the connection disconnects. - - -## disconnect - -Disconnect. - - bluetoothSerial.disconnect([success], [failure]); - -### Description - -Function `disconnect` disconnects the current connection. - -### Parameters - -- __success__: Success callback function that is invoked when the connection is successful. [optional] -- __failure__: Error callback function, invoked when error occurs. [optional] - -## write - -Writes data to the serial port. - - bluetoothSerial.write(data, success, failure); - -### Description - -Function `write` data to the serial port. Data can be an ArrayBuffer, string, array of integers, or a Uint8Array. - -Internally string, integer array, and Uint8Array are converted to an ArrayBuffer. String conversion assume 8bit characters. - -### Parameters - -- __data__: ArrayBuffer of data -- __success__: Success callback function that is invoked when the connection is successful. [optional] -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - // string - bluetoothSerial.write("hello, world", success, failure); - - // array of int (or bytes) - bluetoothSerial.write([186, 220, 222], success, failure); - - // Typed Array - var data = new Uint8Array(4); - data[0] = 0x41; - data[1] = 0x42; - data[2] = 0x43; - data[3] = 0x44; - bluetoothSerial.write(data, success, failure); - - // Array Buffer - bluetoothSerial.write(data.buffer, success, failure); - -## available - -Gets the number of bytes of data available. - - bluetoothSerial.available(success, failure); - -### Description - -Function `available` gets the number of bytes of data available. The bytes are passed as a parameter to the success callback. - -### Parameters - -- __success__: Success callback function that is invoked when the connection is successful. [optional] -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - bluetoothSerial.available(function (numBytes) { - console.log("There are " + numBytes + " available to read."); - }, failure); - -## read - -Reads data from the buffer. - - bluetoothSerial.read(success, failure); - -### Description - -Function `read` reads the data from the buffer. The data is passed to the success callback as a String. Calling `read` when no data is available will pass an empty String to the callback. - -### Parameters - -- __success__: Success callback function that is invoked with the number of bytes available to be read. -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - bluetoothSerial.read(function (data) { - console.log(data); - }, failure); - -## readUntil - -Reads data from the buffer until it reaches a delimiter. - - bluetoothSerial.readUntil('\n', success, failure); - -### Description - -Function `readUntil` reads the data from the buffer until it reaches a delimiter. The data is passed to the success callback as a String. If the buffer does not contain the delimiter, an empty String is passed to the callback. Calling `read` when no data is available will pass an empty String to the callback. - -### Parameters - -- __delimiter__: delimiter -- __success__: Success callback function that is invoked with the data. -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - bluetoothSerial.readUntil('\n', function (data) { - console.log(data); - }, failure); - -## subscribe - -Subscribe to be notified when data is received. - - bluetoothSerial.subscribe('\n', success, failure); - -### Description - -Function `subscribe` registers a callback that is called when data is received. A delimiter must be specified. The callback is called with the data as soon as the delimiter string is read. The callback is a long running callback and will exist until `unsubscribe` is called. - -### Parameters - -- __delimiter__: delimiter -- __success__: Success callback function that is invoked with the data. -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - // the success callback is called whenever data is received - bluetoothSerial.subscribe('\n', function (data) { - console.log(data); - }, failure); - -## unsubscribe - -Unsubscribe from a subscription. - - bluetoothSerial.unsubscribe(success, failure); - -### Description - -Function `unsubscribe` removes any notification added by `subscribe` and kills the callback. - -### Parameters - -- __success__: Success callback function that is invoked when the connection is successful. [optional] -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - bluetoothSerial.unsubscribe(); - -## subscribeRawData - -Subscribe to be notified when data is received. - - bluetoothSerial.subscribeRawData(success, failure); - -### Description - -Function `subscribeRawData` registers a callback that is called when data is received. The callback is called immediately when data is received. The data is sent to callback as an ArrayBuffer. The callback is a long running callback and will exist until `unsubscribeRawData` is called. - -### Parameters - -- __success__: Success callback function that is invoked with the data. -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - // the success callback is called whenever data is received - bluetoothSerial.subscribeRawData(function (data) { - var bytes = new Uint8Array(data); - console.log(bytes); - }, failure); - -## unsubscribeRawData - -Unsubscribe from a subscription. - - bluetoothSerial.unsubscribeRawData(success, failure); - -### Description - -Function `unsubscribeRawData` removes any notification added by `subscribeRawData` and kills the callback. - -### Parameters - -- __success__: Success callback function that is invoked when the connection is successful. [optional] -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - bluetoothSerial.unsubscribeRawData(); - -## clear - -Clears data in the buffer. - - bluetoothSerial.clear(success, failure); - -### Description - -Function `clear` removes any data from the receive buffer. - -### Parameters - -- __success__: Success callback function that is invoked when the connection is successful. [optional] -- __failure__: Error callback function, invoked when error occurs. [optional] - -## list - -Lists bonded devices - - bluetoothSerial.list(success, failure); - -### Description - -#### Android - -Function `list` lists the paired Bluetooth devices. The success callback is called with a list of objects. - -Example list passed to success callback. See [BluetoothDevice](http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName\(\)) and [BluetoothClass#getDeviceClass](http://developer.android.com/reference/android/bluetooth/BluetoothClass.html#getDeviceClass\(\)). - - [{ - "class": 276, - "id": "10:BF:48:CB:00:00", - "address": "10:BF:48:CB:00:00", - "name": "Nexus 7" - }, { - "class": 7936, - "id": "00:06:66:4D:00:00", - "address": "00:06:66:4D:00:00", - "name": "RN42" - }] - -#### iOS - -Function `list` lists the discovered Bluetooth Low Energy peripheral. The success callback is called with a list of objects. - -Example list passed to success callback for iOS. - - [{ - "id": "CC410A23-2865-F03E-FC6A-4C17E858E11E", - "uuid": "CC410A23-2865-F03E-FC6A-4C17E858E11E", - "name": "Biscuit", - "rssi": -68 - }] - -The advertised RSSI **may** be included if available. - -#### Windows Phone - -Function `list` lists the paired Bluetooth devices. The success callback is called with a list of objects. - -Example list passed to success callback for Windows Phone. - - [{ - "id": "(10:BF:48:CB:00:00)", - "name": "Nexus 7" - }, { - "id": "(00:06:66:4D:00:00)", - "name": "RN42" - }] - -### Note - -`id` is the generic name for `uuid` or [mac]`address` so that code can be platform independent. - -### Parameters - -- __success__: Success callback function that is invoked with a list of bonded devices. -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - bluetoothSerial.list(function(devices) { - devices.forEach(function(device) { - console.log(device.id); - }) - }, failure); - -## isConnected - -Reports the connection status. - - bluetoothSerial.isConnected(success, failure); - -### Description - -Function `isConnected` calls the success callback when connected to a peer and the failure callback when *not* connected. - -### Parameters - -- __success__: Success callback function, invoked when device connected. -- __failure__: Error callback function, invoked when device is NOT connected. - -### Quick Example - - bluetoothSerial.isConnected( - function() { - console.log("Bluetooth is connected"); - }, - function() { - console.log("Bluetooth is *not* connected"); - } - ); - -## isEnabled - -Reports if bluetooth is enabled. - - bluetoothSerial.isEnabled(success, failure); - -### Description - -Function `isEnabled` calls the success callback when bluetooth is enabled and the failure callback when bluetooth is *not* enabled. - -### Parameters - -- __success__: Success callback function, invoked when Bluetooth is enabled. -- __failure__: Error callback function, invoked when Bluetooth is NOT enabled. - -### Quick Example - - bluetoothSerial.isEnabled( - function() { - console.log("Bluetooth is enabled"); - }, - function() { - console.log("Bluetooth is *not* enabled"); - } - ); - -## readRSSI - -Reads the RSSI from the connected peripheral. - - bluetoothSerial.readRSSI(success, failure); - -### Description - -Function `readRSSI` calls the success callback with the rssi. - -**BLE only** *This function is experimental and the API may change* - -### Parameters - -- __success__: Success callback function that is invoked with the rssi value. -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - bluetoothSerial.readRSSI( - function(rssi) { - console.log(rssi); - } - ); - -## showBluetoothSettings - -Show the Bluetooth settings on the device. - - bluetoothSerial.showBluetoothSettings(success, failure); - -### Description - -Function `showBluetoothSettings` opens the Bluetooth settings on the operating systems. - -#### iOS - -`showBluetoothSettings` is not supported on iOS. - -### Parameters - -- __success__: Success callback function [optional] -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - bluetoothSerial.showBluetoothSettings(); - -## enable - -Enable Bluetooth on the device. - - bluetoothSerial.enable(success, failure); - -### Description - -Function `enable` prompts the user to enable Bluetooth. - -#### Android - -`enable` is only supported on Android and does not work on iOS or Windows Phone. - -If `enable` is called when Bluetooth is already enabled, the user will not prompted and the success callback will be invoked. - -### Parameters - -- __success__: Success callback function, invoked if the user enabled Bluetooth. -- __failure__: Error callback function, invoked if the user does not enabled Bluetooth. - -### Quick Example - - bluetoothSerial.enable( - function() { - console.log("Bluetooth is enabled"); - }, - function() { - console.log("The user did *not* enable Bluetooth"); - } - ); - -## discoverUnpaired - -Discover unpaired devices - - bluetoothSerial.discoverUnpaired(success, failure); - -### Description - -#### Android - -Function `discoverUnpaired` discovers unpaired Bluetooth devices. The success callback is called with a list of objects similar to `list`, or an empty list if no unpaired devices are found. - -Example list passed to success callback. - - [{ - "class": 276, - "id": "10:BF:48:CB:00:00", - "address": "10:BF:48:CB:00:00", - "name": "Nexus 7" - }, { - "class": 7936, - "id": "00:06:66:4D:00:00", - "address": "00:06:66:4D:00:00", - "name": "RN42" - }] - -The discovery process takes a while to happen. You can register notify callback with [setDeviceDiscoveredListener](#setdevicediscoveredlistener). -You may also want to show a progress indicator while waiting for the discover proces to finish, and the sucess callback to be invoked. - -Calling `connect` on an unpaired Bluetooth device should begin the Android pairing process. - -#### iOS - -`discoverUnpaired` is not supported on iOS. iOS uses Bluetooth Low Energy and `list` discovers devices without pairing. - -#### Windows Phone - -`discoverUnpaired` is not supported on Windows Phone. - -### Parameters - -- __success__: Success callback function that is invoked with a list of unpaired devices. -- __failure__: Error callback function, invoked when error occurs. [optional] - -### Quick Example - - bluetoothSerial.discoverUnpaired(function(devices) { - devices.forEach(function(device) { - console.log(device.id); - }) - }, failure); - -## setDeviceDiscoveredListener - -Register a notify callback function to be called during bluetooth device discovery. For callback to work, discovery process must -be started with [discoverUnpaired](#discoverunpaired). -There can be only one registered callback. - -Example object passed to notify callback. - - { - "class": 276, - "id": "10:BF:48:CB:00:00", - "address": "10:BF:48:CB:00:00", - "name": "Nexus 7" - } - -#### iOS & Windows Phone - -See [discoverUnpaired](#discoverunpaired). - -### Parameters - -- __notify__: Notify callback function that is invoked when device is discovered during discovery process. - -### Quick Example - - bluetoothSerial.setDeviceDiscoveredListener(function(device) { - console.log('Found: '+device.id); - }); - -## clearDeviceDiscoveredListener - -Clears notify callback function registered with [setDeviceDiscoveredListener](#setdevicediscoveredlistener). - -### Quick Example - - bluetoothSerial.clearDeviceDiscoveredListener(); - -## setName - -Sets the human readable device name that is broadcasted to other devices. - - bluetoothSerial.setName(newName); - -#### Android -For Android, `setName` takes a String for the new name. - -#### iOS -Not currently implemented. - -#### Windows Phone -Not currently implemented. - -### Parameters - -- __newName__: Desired name of device. - -### Quick Example - - bluetoothSerial.setName("Really cool name"); - -## setDiscoverable - -Makes the device discoverable by other devices. - - bluetoothSerial.setDiscoverable(discoverableDuration); - -#### Android -For Android, `setDiscoverable` takes an int for the number of seconds device should be discoverable. A time of 0 will make it permanently discoverable. - -#### iOS -Not currently implemented. - -#### Windows Phone -Not currently implemented. - -### Parameters - -- __discoverableDuration__: Desired number of seconds device should be discoverable for. - -### Quick Example - - bluetoothSerial.setDiscoverable(0); - -# Misc - -## Where does this work? - -### Android - -Current development is done with Cordova 4.2 on Android 5. Theoretically this code runs on PhoneGap 2.9 and greater. It should support Android-10 (2.3.2) and greater, but I only test with Android 4.x+. - -Development Devices include - * Nexus 5 with Android 5 - * Samsung Galaxy Tab 10.1 (GT-P7510) with Android 4.0.4 (see [Issue #8](https://github.com/don/BluetoothSerial/issues/8)) - * Google Nexus S with Android 4.1.2 - * Nexus 4 with Android 5 - * Samsung Galaxy S4 with Android 4.3 - -On the Arduino side I test with [Sparkfun Mate Silver](https://www.sparkfun.com/products/10393) and the [Seeed Studio Bluetooth Shield](http://www.seeedstudio.com/depot/bluetooth-shield-p-866.html?cPath=19_21). The code should be generic and work with most hardware. - -I highly recommend [Adafruit's Bluefruit EZ-Link](http://www.adafruit.com/products/1588). - -### iOS - -**NOTE: Currently iOS only works with RedBear Labs Hardware, Adafruit Bluefruit LE, Laird BL600, and BlueGiga UART services** - -This plugin was originally developed with Cordova 3.4 using iOS 7.x on an iPhone 5s connecting to a [RedBearLab BLEMini](http://redbearlab.com/blemini). Ensure that you have update the BLE Mini firmware to at least [Biscuit-UART_20130313.bin](https://github.com/RedBearLab/Biscuit/tree/master/release). - -Most development is now done with iOS 8 with Cordova 4.2 using [RedBear Lab BLE Shield](http://redbearlab.com/bleshield/) or [Adafruit Bluefruit LE Friend](https://www.adafruit.com/product/2267). - -### Supporting other BLE hardware - -For Bluetooth Low Energy, this plugin supports some hardware running known UART-like services, but can support any Bluetooth Low Energy hardware with a "serial like" service. This means a transmit characteristic that is writable and a receive characteristic that supports notification. - -Edit [BLEdefines.h](src/ios/BLEDefines.h) and adjust the UUIDs for your service. - -See [Issue 141](https://github.com/don/BluetoothSerial/issues/141#issuecomment-161500473) for details on how to add support for Amp'ed RF Technology BT43H. - -## Props - -### Android - -Most of the Bluetooth implementation was borrowed from the Bluetooth Chat example in the Android SDK. - -### iOS - -The iOS code uses RedBearLab's [BLE_Framework](https://github.com/RedBearLab/iOS/tree/master/BLEFramework/BLE). - -### API - -The API for available, read, readUntil was influenced by the [BtSerial Library for Processing for Arduino](https://github.com/arduino/BtSerial) - -## Wrong Bluetooth Plugin? - -If you don't need **serial** over Bluetooth, try the [PhoneGap Bluetooth Plugin for Android](https://github.com/phonegap/phonegap-plugins/tree/DEPRECATED/Android/Bluetooth/2.2.0) or perhaps [phonegap-plugin-bluetooth](https://github.com/tanelih/phonegap-bluetooth-plugin). - -If you need generic Bluetooth Low Energy support checkout my [Cordova BLE Plugin](https://github.com/don/cordova-plugin-ble-central). - -If you need BLE for RFduino checkout my [RFduino Plugin](https://github.com/don/cordova-plugin-rfduino). - -## What format should the Mac Address be in? -An example a properly formatted mac address is ``AA:BB:CC:DD:EE:FF`` - -## Feedback - -Try the code. If you find an problem or missing feature, file an issue or create a pull request. +# Bluetooth Serial Plugin for PhoneGap + +This plugin enables serial communication over Bluetooth. It was written for communicating between Android or iOS and an Arduino. + +Android and Windows Phone use Classic Bluetooth. iOS uses Bluetooth Low Energy. + +## Supported Platforms + +* Android +* iOS with [RedBearLab](http://redbearlab.com) BLE hardware, [Adafruit Bluefruit LE](http://www.adafruit.com/products/1697), [Laird BL600](http://www.lairdtech.com/Products/Embedded-Wireless-Solutions/Bluetooth-Radio-Modules/BL600-Series/#.VBI7AS5dUzI), or [BlueGiga](https://bluegiga.zendesk.com/entries/29185293--BGScript-spp-over-ble-AT-command-SPP-implementation-for-BLE) +* Windows Phone 8 +* Browser (Testing only. See [comments](https://github.com/don/BluetoothSerial/blob/master/src/browser/bluetoothSerial.js).) + +[Supporting other Bluetooth Low Energy hardware](#supporting-other-ble-hardware) + +## Limitations + + * The phone must initiate the Bluetooth connection + * iOS Bluetooth Low Energy requires iPhone 4S, iPhone5, iPod 5, or iPad3+ + * Will *not* connect Android to Android[*](https://github.com/don/BluetoothSerial/issues/50#issuecomment-66405396) + * Will *not* connect iOS to iOS[*](https://github.com/don/BluetoothSerial/issues/75#issuecomment-52591397) + * Multiple connections works only on Android + +# Installing + +Install with Cordova cli + + $ cordova plugin add cordova-plugin-bluetooth-serial + +Note that this plugin's id changed from `com.megster.cordova.bluetoothserial` to `cordova-plugin-bluetooth-serial` as part of the migration from the [Cordova plugin repo](http://plugins.cordova.io/) to [npm](https://www.npmjs.com/). + +# Examples + +There are some [sample projects](https://github.com/don/BluetoothSerial/tree/master/examples) included with the plugin. + +# API + +## Methods + +- [bluetoothSerial.connect](#connect) +- [bluetoothSerial.connectInsecure](#connectInsecure) +- [bluetoothSerial.disconnect](#disconnect) +- [bluetoothSerial.write](#write) +- [bluetoothSerial.available](#available) +- [bluetoothSerial.read](#read) +- [bluetoothSerial.readUntil](#readuntil) +- [bluetoothSerial.subscribe](#subscribe) +- [bluetoothSerial.unsubscribe](#unsubscribe) +- [bluetoothSerial.subscribeRawData](#subscriberawdata) +- [bluetoothSerial.unsubscribeRawData](#unsubscriberawdata) +- [bluetoothSerial.clear](#clear) +- [bluetoothSerial.list](#list) +- [bluetoothSerial.isEnabled](#isenabled) +- [bluetoothSerial.isConnected](#isconnected) +- [bluetoothSerial.readRSSI](#readrssi) +- [bluetoothSerial.showBluetoothSettings](#showbluetoothsettings) +- [bluetoothSerial.enable](#enable) +- [bluetoothSerial.discoverUnpaired](#discoverunpaired) +- [bluetoothSerial.setDeviceDiscoveredListener](#setdevicediscoveredlistener) +- [bluetoothSerial.clearDeviceDiscoveredListener](#cleardevicediscoveredlistener) +- [bluetoothSerial.setName](#setname) +- [bluetoothSerial.setDiscoverable](#setdiscoverable) + +## connect + +Connect to a Bluetooth device. + + bluetoothSerial.connect(macAddress_or_uuid, connectSuccess, connectFailure); + +### Description + +Function `connect` connects to a Bluetooth device. The callback is long running. Success will be called when the connection is successful. Failure is called if the connection fails, or later if the connection disconnects. An error message is passed to the failure callback. + +#### Android +For Android, `connect` takes a MAC address of the remote device. + +#### iOS +For iOS, `connect` takes the UUID of the remote device. Optionally, you can pass an **empty string** and the plugin will connect to the first BLE peripheral. + +#### Windows Phone +For Windows Phone, `connect` takes a MAC address of the remote device. The MAC address can optionally surrounded with parenthesis. e.g. `(AA:BB:CC:DD:EE:FF)` + + +### Parameters + +- __macAddress_or_uuid__: Identifier of the remote device. +- __connectSuccess__: Success callback function that is invoked when the connection is successful. +- __connectFailure__: Error callback function, invoked when error occurs or the connection disconnects. + +## connectInsecure + +Connect insecurely to a Bluetooth device. + + bluetoothSerial.connectInsecure(macAddress, connectSuccess, connectFailure); + +### Description + +Function `connectInsecure` works like [connect](#connect), but creates an insecure connection to a Bluetooth device. See the [Android docs](http://goo.gl/1mFjZY) for more information. + +#### Android +For Android, `connectInsecure` takes a macAddress of the remote device. + +#### iOS +`connectInsecure` is **not supported** on iOS. + +#### Windows Phone +`connectInsecure` is **not supported** on Windows Phone. + +### Parameters + +- __macAddress__: Identifier of the remote device. +- __connectSuccess__: Success callback function that is invoked when the connection is successful. +- __connectFailure__: Error callback function, invoked when error occurs or the connection disconnects. + + +## disconnect + +Disconnect. + + bluetoothSerial.disconnect([success], [failure], [macAddress]); + +### Description + +Function `disconnect` disconnects the current connection. + +### Parameters + +- __success__: Success callback function that is invoked when the connection is successful. [optional] +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +## write + +Writes data to the serial port. + + bluetoothSerial.write(data, success, failure, [macAddress]); + +### Description + +Function `write` data to the serial port. Data can be an ArrayBuffer, string, array of integers, or a Uint8Array. + +Internally string, integer array, and Uint8Array are converted to an ArrayBuffer. String conversion assume 8bit characters. + +### Parameters + +- __data__: ArrayBuffer of data +- __success__: Success callback function that is invoked when the connection is successful. [optional] +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +### Quick Example + + // string + bluetoothSerial.write("hello, world", success, failure); + + // array of int (or bytes) + bluetoothSerial.write([186, 220, 222], success, failure); + + // Typed Array + var data = new Uint8Array(4); + data[0] = 0x41; + data[1] = 0x42; + data[2] = 0x43; + data[3] = 0x44; + bluetoothSerial.write(data, success, failure); + + // Array Buffer + bluetoothSerial.write(data.buffer, success, failure); + +## available + +Gets the number of bytes of data available. + + bluetoothSerial.available(success, failure, [macAddress]); + +### Description + +Function `available` gets the number of bytes of data available. The bytes are passed as a parameter to the success callback. + +### Parameters + +- __success__: Success callback function that is invoked when the connection is successful. [optional] +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +### Quick Example + + bluetoothSerial.available(function (numBytes) { + console.log("There are " + numBytes + " available to read."); + }, failure); + +## read + +Reads data from the buffer. + + bluetoothSerial.read(success, failure, [macAddress]); + +### Description + +Function `read` reads the data from the buffer. The data is passed to the success callback as a String. Calling `read` when no data is available will pass an empty String to the callback. + +### Parameters + +- __success__: Success callback function that is invoked with the number of bytes available to be read. +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +### Quick Example + + bluetoothSerial.read(function (data) { + console.log(data); + }, failure); + +## readUntil + +Reads data from the buffer until it reaches a delimiter. + + bluetoothSerial.readUntil('\n', success, failure, [macAddress]); + +### Description + +Function `readUntil` reads the data from the buffer until it reaches a delimiter. The data is passed to the success callback as a String. If the buffer does not contain the delimiter, an empty String is passed to the callback. Calling `read` when no data is available will pass an empty String to the callback. + +### Parameters + +- __delimiter__: delimiter +- __success__: Success callback function that is invoked with the data. +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +### Quick Example + + bluetoothSerial.readUntil('\n', function (data) { + console.log(data); + }, failure); + +## subscribe + +Subscribe to be notified when data is received. + + bluetoothSerial.subscribe('\n', success, failure, [macAddress]); + +### Description + +Function `subscribe` registers a callback that is called when data is received. A delimiter must be specified. The callback is called with the data as soon as the delimiter string is read. The callback is a long running callback and will exist until `unsubscribe` is called. + +### Parameters + +- __delimiter__: delimiter +- __success__: Success callback function that is invoked with the data. +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +### Quick Example + + // the success callback is called whenever data is received + bluetoothSerial.subscribe('\n', function (data) { + console.log(data); + }, failure); + +## unsubscribe + +Unsubscribe from a subscription. + + bluetoothSerial.unsubscribe(success, failure, [macAddress]); + +### Description + +Function `unsubscribe` removes any notification added by `subscribe` and kills the callback. + +### Parameters + +- __success__: Success callback function that is invoked when the connection is successful. [optional] +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +### Quick Example + + bluetoothSerial.unsubscribe(); + +## subscribeRawData + +Subscribe to be notified when data is received. + + bluetoothSerial.subscribeRawData(success, failure, [macAddress]); + +### Description + +Function `subscribeRawData` registers a callback that is called when data is received. The callback is called immediately when data is received. The data is sent to callback as an ArrayBuffer. The callback is a long running callback and will exist until `unsubscribeRawData` is called. + +### Parameters + +- __success__: Success callback function that is invoked with the data. +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +### Quick Example + + // the success callback is called whenever data is received + bluetoothSerial.subscribeRawData(function (data) { + var bytes = new Uint8Array(data); + console.log(bytes); + }, failure); + +## unsubscribeRawData + +Unsubscribe from a subscription. + + bluetoothSerial.unsubscribeRawData(success, failure, [macAddress]); + +### Description + +Function `unsubscribeRawData` removes any notification added by `subscribeRawData` and kills the callback. + +### Parameters + +- __success__: Success callback function that is invoked when the connection is successful. [optional] +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +### Quick Example + + bluetoothSerial.unsubscribeRawData(); + +## clear + +Clears data in the buffer. + + bluetoothSerial.clear(success, failure, [macAddress]); + +### Description + +Function `clear` removes any data from the receive buffer. + +### Parameters + +- __success__: Success callback function that is invoked when the connection is successful. [optional] +- __failure__: Error callback function, invoked when error occurs. [optional] +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +## list + +Lists bonded devices + + bluetoothSerial.list(success, failure); + +### Description + +#### Android + +Function `list` lists the paired Bluetooth devices. The success callback is called with a list of objects. + +Example list passed to success callback. See [BluetoothDevice](http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName\(\)) and [BluetoothClass#getDeviceClass](http://developer.android.com/reference/android/bluetooth/BluetoothClass.html#getDeviceClass\(\)). + + [{ + "class": 276, + "id": "10:BF:48:CB:00:00", + "address": "10:BF:48:CB:00:00", + "name": "Nexus 7" + }, { + "class": 7936, + "id": "00:06:66:4D:00:00", + "address": "00:06:66:4D:00:00", + "name": "RN42" + }] + +#### iOS + +Function `list` lists the discovered Bluetooth Low Energy peripheral. The success callback is called with a list of objects. + +Example list passed to success callback for iOS. + + [{ + "id": "CC410A23-2865-F03E-FC6A-4C17E858E11E", + "uuid": "CC410A23-2865-F03E-FC6A-4C17E858E11E", + "name": "Biscuit", + "rssi": -68 + }] + +The advertised RSSI **may** be included if available. + +#### Windows Phone + +Function `list` lists the paired Bluetooth devices. The success callback is called with a list of objects. + +Example list passed to success callback for Windows Phone. + + [{ + "id": "(10:BF:48:CB:00:00)", + "name": "Nexus 7" + }, { + "id": "(00:06:66:4D:00:00)", + "name": "RN42" + }] + +### Note + +`id` is the generic name for `uuid` or [mac]`address` so that code can be platform independent. + +### Parameters + +- __success__: Success callback function that is invoked with a list of bonded devices. +- __failure__: Error callback function, invoked when error occurs. [optional] + +### Quick Example + + bluetoothSerial.list(function(devices) { + devices.forEach(function(device) { + console.log(device.id); + }) + }, failure); + +## isConnected + +Reports the connection status. + + bluetoothSerial.isConnected(success, failure, [macAddress]); + +### Description + +Function `isConnected` calls the success callback when connected to a peer and the failure callback when *not* connected. + +### Parameters + +- __success__: Success callback function, invoked when device connected. +- __failure__: Error callback function, invoked when device is NOT connected. +- __macAddress__: Identifier of the remote device, if not specified the identifier of the last connect or connectInsecure is used. [optional] + +### Quick Example + + bluetoothSerial.isConnected( + function() { + console.log("Bluetooth is connected"); + }, + function() { + console.log("Bluetooth is *not* connected"); + } + ); + +## isEnabled + +Reports if bluetooth is enabled. + + bluetoothSerial.isEnabled(success, failure); + +### Description + +Function `isEnabled` calls the success callback when bluetooth is enabled and the failure callback when bluetooth is *not* enabled. + +### Parameters + +- __success__: Success callback function, invoked when Bluetooth is enabled. +- __failure__: Error callback function, invoked when Bluetooth is NOT enabled. + +### Quick Example + + bluetoothSerial.isEnabled( + function() { + console.log("Bluetooth is enabled"); + }, + function() { + console.log("Bluetooth is *not* enabled"); + } + ); + +## readRSSI + +Reads the RSSI from the connected peripheral. + + bluetoothSerial.readRSSI(success, failure); + +### Description + +Function `readRSSI` calls the success callback with the rssi. + +**BLE only** *This function is experimental and the API may change* + +### Parameters + +- __success__: Success callback function that is invoked with the rssi value. +- __failure__: Error callback function, invoked when error occurs. [optional] + +### Quick Example + + bluetoothSerial.readRSSI( + function(rssi) { + console.log(rssi); + } + ); + +## showBluetoothSettings + +Show the Bluetooth settings on the device. + + bluetoothSerial.showBluetoothSettings(success, failure); + +### Description + +Function `showBluetoothSettings` opens the Bluetooth settings on the operating systems. + +#### iOS + +`showBluetoothSettings` is not supported on iOS. + +### Parameters + +- __success__: Success callback function [optional] +- __failure__: Error callback function, invoked when error occurs. [optional] + +### Quick Example + + bluetoothSerial.showBluetoothSettings(); + +## enable + +Enable Bluetooth on the device. + + bluetoothSerial.enable(success, failure); + +### Description + +Function `enable` prompts the user to enable Bluetooth. + +#### Android + +`enable` is only supported on Android and does not work on iOS or Windows Phone. + +If `enable` is called when Bluetooth is already enabled, the user will not prompted and the success callback will be invoked. + +### Parameters + +- __success__: Success callback function, invoked if the user enabled Bluetooth. +- __failure__: Error callback function, invoked if the user does not enabled Bluetooth. + +### Quick Example + + bluetoothSerial.enable( + function() { + console.log("Bluetooth is enabled"); + }, + function() { + console.log("The user did *not* enable Bluetooth"); + } + ); + +## discoverUnpaired + +Discover unpaired devices + + bluetoothSerial.discoverUnpaired(success, failure); + +### Description + +#### Android + +Function `discoverUnpaired` discovers unpaired Bluetooth devices. The success callback is called with a list of objects similar to `list`, or an empty list if no unpaired devices are found. + +Example list passed to success callback. + + [{ + "class": 276, + "id": "10:BF:48:CB:00:00", + "address": "10:BF:48:CB:00:00", + "name": "Nexus 7" + }, { + "class": 7936, + "id": "00:06:66:4D:00:00", + "address": "00:06:66:4D:00:00", + "name": "RN42" + }] + +The discovery process takes a while to happen. You can register notify callback with [setDeviceDiscoveredListener](#setdevicediscoveredlistener). +You may also want to show a progress indicator while waiting for the discover proces to finish, and the sucess callback to be invoked. + +Calling `connect` on an unpaired Bluetooth device should begin the Android pairing process. + +#### iOS + +`discoverUnpaired` is not supported on iOS. iOS uses Bluetooth Low Energy and `list` discovers devices without pairing. + +#### Windows Phone + +`discoverUnpaired` is not supported on Windows Phone. + +### Parameters + +- __success__: Success callback function that is invoked with a list of unpaired devices. +- __failure__: Error callback function, invoked when error occurs. [optional] + +### Quick Example + + bluetoothSerial.discoverUnpaired(function(devices) { + devices.forEach(function(device) { + console.log(device.id); + }) + }, failure); + +## setDeviceDiscoveredListener + +Register a notify callback function to be called during bluetooth device discovery. For callback to work, discovery process must +be started with [discoverUnpaired](#discoverunpaired). +There can be only one registered callback. + +Example object passed to notify callback. + + { + "class": 276, + "id": "10:BF:48:CB:00:00", + "address": "10:BF:48:CB:00:00", + "name": "Nexus 7" + } + +#### iOS & Windows Phone + +See [discoverUnpaired](#discoverunpaired). + +### Parameters + +- __notify__: Notify callback function that is invoked when device is discovered during discovery process. + +### Quick Example + + bluetoothSerial.setDeviceDiscoveredListener(function(device) { + console.log('Found: '+device.id); + }); + +## clearDeviceDiscoveredListener + +Clears notify callback function registered with [setDeviceDiscoveredListener](#setdevicediscoveredlistener). + +### Quick Example + + bluetoothSerial.clearDeviceDiscoveredListener(); + +## setName + +Sets the human readable device name that is broadcasted to other devices. + + bluetoothSerial.setName(newName); + +#### Android +For Android, `setName` takes a String for the new name. + +#### iOS +Not currently implemented. + +#### Windows Phone +Not currently implemented. + +### Parameters + +- __newName__: Desired name of device. + +### Quick Example + + bluetoothSerial.setName("Really cool name"); + +## setDiscoverable + +Makes the device discoverable by other devices. + + bluetoothSerial.setDiscoverable(discoverableDuration); + +#### Android +For Android, `setDiscoverable` takes an int for the number of seconds device should be discoverable. A time of 0 will make it permanently discoverable. + +#### iOS +Not currently implemented. + +#### Windows Phone +Not currently implemented. + +### Parameters + +- __discoverableDuration__: Desired number of seconds device should be discoverable for. + +### Quick Example + + bluetoothSerial.setDiscoverable(0); + +# Misc + +## Where does this work? + +### Android + +Current development is done with Cordova 4.2 on Android 5. Theoretically this code runs on PhoneGap 2.9 and greater. It should support Android-10 (2.3.2) and greater, but I only test with Android 4.x+. + +Development Devices include + * Nexus 5 with Android 5 + * Samsung Galaxy Tab 10.1 (GT-P7510) with Android 4.0.4 (see [Issue #8](https://github.com/don/BluetoothSerial/issues/8)) + * Google Nexus S with Android 4.1.2 + * Nexus 4 with Android 5 + * Samsung Galaxy S4 with Android 4.3 + +On the Arduino side I test with [Sparkfun Mate Silver](https://www.sparkfun.com/products/10393) and the [Seeed Studio Bluetooth Shield](http://www.seeedstudio.com/depot/bluetooth-shield-p-866.html?cPath=19_21). The code should be generic and work with most hardware. + +I highly recommend [Adafruit's Bluefruit EZ-Link](http://www.adafruit.com/products/1588). + +### iOS + +**NOTE: Currently iOS only works with RedBear Labs Hardware, Adafruit Bluefruit LE, Laird BL600, and BlueGiga UART services** + +This plugin was originally developed with Cordova 3.4 using iOS 7.x on an iPhone 5s connecting to a [RedBearLab BLEMini](http://redbearlab.com/blemini). Ensure that you have update the BLE Mini firmware to at least [Biscuit-UART_20130313.bin](https://github.com/RedBearLab/Biscuit/tree/master/release). + +Most development is now done with iOS 8 with Cordova 4.2 using [RedBear Lab BLE Shield](http://redbearlab.com/bleshield/) or [Adafruit Bluefruit LE Friend](https://www.adafruit.com/product/2267). + +### Supporting other BLE hardware + +For Bluetooth Low Energy, this plugin supports some hardware running known UART-like services, but can support any Bluetooth Low Energy hardware with a "serial like" service. This means a transmit characteristic that is writable and a receive characteristic that supports notification. + +Edit [BLEdefines.h](src/ios/BLEDefines.h) and adjust the UUIDs for your service. + +See [Issue 141](https://github.com/don/BluetoothSerial/issues/141#issuecomment-161500473) for details on how to add support for Amp'ed RF Technology BT43H. + +## Props + +### Android + +Most of the Bluetooth implementation was borrowed from the Bluetooth Chat example in the Android SDK. + +### iOS + +The iOS code uses RedBearLab's [BLE_Framework](https://github.com/RedBearLab/iOS/tree/master/BLEFramework/BLE). + +### API + +The API for available, read, readUntil was influenced by the [BtSerial Library for Processing for Arduino](https://github.com/arduino/BtSerial) + +## Wrong Bluetooth Plugin? + +If you don't need **serial** over Bluetooth, try the [PhoneGap Bluetooth Plugin for Android](https://github.com/phonegap/phonegap-plugins/tree/DEPRECATED/Android/Bluetooth/2.2.0) or perhaps [phonegap-plugin-bluetooth](https://github.com/tanelih/phonegap-bluetooth-plugin). + +If you need generic Bluetooth Low Energy support checkout my [Cordova BLE Plugin](https://github.com/don/cordova-plugin-ble-central). + +If you need BLE for RFduino checkout my [RFduino Plugin](https://github.com/don/cordova-plugin-rfduino). + +## What format should the Mac Address be in? +An example a properly formatted mac address is ``AA:BB:CC:DD:EE:FF`` + +## Feedback + +Try the code. If you find an problem or missing feature, file an issue or create a pull request. diff --git a/src/android/com/megster/cordova/BluetoothSerial.java b/src/android/com/megster/cordova/BluetoothSerial.java index 77fa6119..ef1fc30d 100644 --- a/src/android/com/megster/cordova/BluetoothSerial.java +++ b/src/android/com/megster/cordova/BluetoothSerial.java @@ -1,453 +1,598 @@ -package com.megster.cordova; - -import android.app.Activity; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.os.Message; -import android.provider.Settings; -import android.util.Log; -import org.apache.cordova.CordovaArgs; -import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.CallbackContext; -import org.apache.cordova.PluginResult; -import org.apache.cordova.LOG; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.Set; - -/** - * PhoneGap Plugin for Serial Communication over Bluetooth - */ -public class BluetoothSerial extends CordovaPlugin { - - // actions - private static final String LIST = "list"; - private static final String CONNECT = "connect"; - private static final String CONNECT_INSECURE = "connectInsecure"; - private static final String DISCONNECT = "disconnect"; - private static final String WRITE = "write"; - private static final String AVAILABLE = "available"; - private static final String READ = "read"; - private static final String READ_UNTIL = "readUntil"; - private static final String SUBSCRIBE = "subscribe"; - private static final String UNSUBSCRIBE = "unsubscribe"; - private static final String SUBSCRIBE_RAW = "subscribeRaw"; - private static final String UNSUBSCRIBE_RAW = "unsubscribeRaw"; - private static final String IS_ENABLED = "isEnabled"; - private static final String IS_CONNECTED = "isConnected"; - private static final String CLEAR = "clear"; - private static final String SETTINGS = "showBluetoothSettings"; - private static final String ENABLE = "enable"; - private static final String DISCOVER_UNPAIRED = "discoverUnpaired"; - private static final String SET_DEVICE_DISCOVERED_LISTENER = "setDeviceDiscoveredListener"; - private static final String CLEAR_DEVICE_DISCOVERED_LISTENER = "clearDeviceDiscoveredListener"; - private static final String SET_NAME = "setName"; - private static final String SET_DISCOVERABLE = "setDiscoverable"; - - // callbacks - private CallbackContext connectCallback; - private CallbackContext dataAvailableCallback; - private CallbackContext rawDataAvailableCallback; - private CallbackContext enableBluetoothCallback; - private CallbackContext deviceDiscoveredCallback; - - private BluetoothAdapter bluetoothAdapter; - private BluetoothSerialService bluetoothSerialService; - - // Debugging - private static final String TAG = "BluetoothSerial"; - private static final boolean D = true; - - // Message types sent from the BluetoothSerialService Handler - public static final int MESSAGE_STATE_CHANGE = 1; - public static final int MESSAGE_READ = 2; - public static final int MESSAGE_WRITE = 3; - public static final int MESSAGE_DEVICE_NAME = 4; - public static final int MESSAGE_TOAST = 5; - public static final int MESSAGE_READ_RAW = 6; - - // Key names received from the BluetoothChatService Handler - public static final String DEVICE_NAME = "device_name"; - public static final String TOAST = "toast"; - - StringBuffer buffer = new StringBuffer(); - private String delimiter; - private static final int REQUEST_ENABLE_BLUETOOTH = 1; - - @Override - public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException { - - LOG.d(TAG, "action = " + action); - - if (bluetoothAdapter == null) { - bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - } - - if (bluetoothSerialService == null) { - bluetoothSerialService = new BluetoothSerialService(mHandler); - } - - boolean validAction = true; - - if (action.equals(LIST)) { - - listBondedDevices(callbackContext); - - } else if (action.equals(CONNECT)) { - - boolean secure = true; - connect(args, secure, callbackContext); - - } else if (action.equals(CONNECT_INSECURE)) { - - // see Android docs about Insecure RFCOMM http://goo.gl/1mFjZY - boolean secure = false; - connect(args, secure, callbackContext); - - } else if (action.equals(DISCONNECT)) { - - connectCallback = null; - bluetoothSerialService.stop(); - callbackContext.success(); - - } else if (action.equals(WRITE)) { - - byte[] data = args.getArrayBuffer(0); - bluetoothSerialService.write(data); - callbackContext.success(); - - } else if (action.equals(AVAILABLE)) { - - callbackContext.success(available()); - - } else if (action.equals(READ)) { - - callbackContext.success(read()); - - } else if (action.equals(READ_UNTIL)) { - - String interesting = args.getString(0); - callbackContext.success(readUntil(interesting)); - - } else if (action.equals(SUBSCRIBE)) { - - delimiter = args.getString(0); - dataAvailableCallback = callbackContext; - - PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); - result.setKeepCallback(true); - callbackContext.sendPluginResult(result); - - } else if (action.equals(UNSUBSCRIBE)) { - - delimiter = null; - - // send no result, so Cordova won't hold onto the data available callback anymore - PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); - dataAvailableCallback.sendPluginResult(result); - dataAvailableCallback = null; - - callbackContext.success(); - - } else if (action.equals(SUBSCRIBE_RAW)) { - - rawDataAvailableCallback = callbackContext; - - PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); - result.setKeepCallback(true); - callbackContext.sendPluginResult(result); - - } else if (action.equals(UNSUBSCRIBE_RAW)) { - - rawDataAvailableCallback = null; - - callbackContext.success(); - - } else if (action.equals(IS_ENABLED)) { - - if (bluetoothAdapter.isEnabled()) { - callbackContext.success(); - } else { - callbackContext.error("Bluetooth is disabled."); - } - - } else if (action.equals(IS_CONNECTED)) { - - if (bluetoothSerialService.getState() == BluetoothSerialService.STATE_CONNECTED) { - callbackContext.success(); - } else { - callbackContext.error("Not connected."); - } - - } else if (action.equals(CLEAR)) { - - buffer.setLength(0); - callbackContext.success(); - - } else if (action.equals(SETTINGS)) { - - Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS); - cordova.getActivity().startActivity(intent); - callbackContext.success(); - - } else if (action.equals(ENABLE)) { - - enableBluetoothCallback = callbackContext; - Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); - cordova.startActivityForResult(this, intent, REQUEST_ENABLE_BLUETOOTH); - - } else if (action.equals(DISCOVER_UNPAIRED)) { - - discoverUnpairedDevices(callbackContext); - - } else if (action.equals(SET_DEVICE_DISCOVERED_LISTENER)) { - - this.deviceDiscoveredCallback = callbackContext; - - } else if (action.equals(CLEAR_DEVICE_DISCOVERED_LISTENER)) { - - this.deviceDiscoveredCallback = null; - - } else if (action.equals(SET_NAME)) { - - String newName = args.getString(0); - bluetoothAdapter.setName(newName); - callbackContext.success(); - - } else if (action.equals(SET_DISCOVERABLE)) { - - int discoverableDuration = args.getInt(0); - Intent discoverIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); - discoverIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, discoverableDuration); - cordova.getActivity().startActivity(discoverIntent); - - } else { - validAction = false; - - } - - return validAction; - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - - if (requestCode == REQUEST_ENABLE_BLUETOOTH) { - - if (resultCode == Activity.RESULT_OK) { - Log.d(TAG, "User enabled Bluetooth"); - if (enableBluetoothCallback != null) { - enableBluetoothCallback.success(); - } - } else { - Log.d(TAG, "User did *NOT* enable Bluetooth"); - if (enableBluetoothCallback != null) { - enableBluetoothCallback.error("User did not enable Bluetooth"); - } - } - - enableBluetoothCallback = null; - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (bluetoothSerialService != null) { - bluetoothSerialService.stop(); - } - } - - private void listBondedDevices(CallbackContext callbackContext) throws JSONException { - JSONArray deviceList = new JSONArray(); - Set bondedDevices = bluetoothAdapter.getBondedDevices(); - - for (BluetoothDevice device : bondedDevices) { - deviceList.put(deviceToJSON(device)); - } - callbackContext.success(deviceList); - } - - private void discoverUnpairedDevices(final CallbackContext callbackContext) throws JSONException { - - final CallbackContext ddc = deviceDiscoveredCallback; - - final BroadcastReceiver discoverReceiver = new BroadcastReceiver() { - - private JSONArray unpairedDevices = new JSONArray(); - - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (BluetoothDevice.ACTION_FOUND.equals(action)) { - BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - try { - JSONObject o = deviceToJSON(device); - unpairedDevices.put(o); - if (ddc != null) { - PluginResult res = new PluginResult(PluginResult.Status.OK, o); - res.setKeepCallback(true); - ddc.sendPluginResult(res); - } - } catch (JSONException e) { - // This shouldn't happen, log and ignore - Log.e(TAG, "Problem converting device to JSON", e); - } - } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { - callbackContext.success(unpairedDevices); - cordova.getActivity().unregisterReceiver(this); - } - } - }; - - Activity activity = cordova.getActivity(); - activity.registerReceiver(discoverReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND)); - activity.registerReceiver(discoverReceiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)); - bluetoothAdapter.startDiscovery(); - } - - private JSONObject deviceToJSON(BluetoothDevice device) throws JSONException { - JSONObject json = new JSONObject(); - json.put("name", device.getName()); - json.put("address", device.getAddress()); - json.put("id", device.getAddress()); - if (device.getBluetoothClass() != null) { - json.put("class", device.getBluetoothClass().getDeviceClass()); - } - return json; - } - - private void connect(CordovaArgs args, boolean secure, CallbackContext callbackContext) throws JSONException { - String macAddress = args.getString(0); - BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAddress); - - if (device != null) { - connectCallback = callbackContext; - bluetoothSerialService.connect(device, secure); - - PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); - result.setKeepCallback(true); - callbackContext.sendPluginResult(result); - - } else { - callbackContext.error("Could not connect to " + macAddress); - } - } - - // The Handler that gets information back from the BluetoothSerialService - // Original code used handler for the because it was talking to the UI. - // Consider replacing with normal callbacks - private final Handler mHandler = new Handler() { - - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_READ: - buffer.append((String)msg.obj); - - if (dataAvailableCallback != null) { - sendDataToSubscriber(); - } - - break; - case MESSAGE_READ_RAW: - if (rawDataAvailableCallback != null) { - byte[] bytes = (byte[]) msg.obj; - sendRawDataToSubscriber(bytes); - } - break; - case MESSAGE_STATE_CHANGE: - - if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); - switch (msg.arg1) { - case BluetoothSerialService.STATE_CONNECTED: - Log.i(TAG, "BluetoothSerialService.STATE_CONNECTED"); - notifyConnectionSuccess(); - break; - case BluetoothSerialService.STATE_CONNECTING: - Log.i(TAG, "BluetoothSerialService.STATE_CONNECTING"); - break; - case BluetoothSerialService.STATE_LISTEN: - Log.i(TAG, "BluetoothSerialService.STATE_LISTEN"); - break; - case BluetoothSerialService.STATE_NONE: - Log.i(TAG, "BluetoothSerialService.STATE_NONE"); - break; - } - break; - case MESSAGE_WRITE: - // byte[] writeBuf = (byte[]) msg.obj; - // String writeMessage = new String(writeBuf); - // Log.i(TAG, "Wrote: " + writeMessage); - break; - case MESSAGE_DEVICE_NAME: - Log.i(TAG, msg.getData().getString(DEVICE_NAME)); - break; - case MESSAGE_TOAST: - String message = msg.getData().getString(TOAST); - notifyConnectionLost(message); - break; - } - } - }; - - private void notifyConnectionLost(String error) { - if (connectCallback != null) { - connectCallback.error(error); - connectCallback = null; - } - } - - private void notifyConnectionSuccess() { - if (connectCallback != null) { - PluginResult result = new PluginResult(PluginResult.Status.OK); - result.setKeepCallback(true); - connectCallback.sendPluginResult(result); - } - } - - private void sendRawDataToSubscriber(byte[] data) { - if (data != null && data.length > 0) { - PluginResult result = new PluginResult(PluginResult.Status.OK, data); - result.setKeepCallback(true); - rawDataAvailableCallback.sendPluginResult(result); - } - } - - private void sendDataToSubscriber() { - String data = readUntil(delimiter); - if (data != null && data.length() > 0) { - PluginResult result = new PluginResult(PluginResult.Status.OK, data); - result.setKeepCallback(true); - dataAvailableCallback.sendPluginResult(result); - - sendDataToSubscriber(); - } - } - - private int available() { - return buffer.length(); - } - - private String read() { - int length = buffer.length(); - String data = buffer.substring(0, length); - buffer.delete(0, length); - return data; - } - - private String readUntil(String c) { - String data = ""; - int index = buffer.indexOf(c, 0); - if (index > -1) { - data = buffer.substring(0, index + c.length()); - buffer.delete(0, index + c.length()); - } - return data; - } -} +package com.megster.cordova; + +import android.app.Activity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.Message; +import android.provider.Settings; +import android.util.Log; +import org.apache.cordova.CordovaArgs; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.CallbackContext; +import org.apache.cordova.PluginResult; +import org.apache.cordova.LOG; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Set; + +/** + * PhoneGap Plugin for Serial Communication over Bluetooth + */ +public class BluetoothSerial extends CordovaPlugin { + + + + private class ConnectionContext{ + + // callbacks + public CallbackContext connectCallback; + public CallbackContext dataAvailableCallback; + public CallbackContext rawDataAvailableCallback; + + + public BluetoothSerialService bluetoothSerialService; + + + StringBuffer buffer = new StringBuffer(); + private String delimiter; + + + public ConnectionContext() + { + bluetoothSerialService = new BluetoothSerialService(mHandler); + } + + private void notifyConnectionLost(String error) { + if (connectCallback != null) { + connectCallback.error(error); + connectCallback = null; + } + } + + private void notifyConnectionSuccess() { + if (connectCallback != null) { + PluginResult result = new PluginResult(PluginResult.Status.OK); + result.setKeepCallback(true); + connectCallback.sendPluginResult(result); + } + } + + private void sendRawDataToSubscriber(byte[] data) { + if (data != null && data.length > 0) { + PluginResult result = new PluginResult(PluginResult.Status.OK, data); + result.setKeepCallback(true); + rawDataAvailableCallback.sendPluginResult(result); + } + } + + private void sendDataToSubscriber() { + String data = readUntil(delimiter); + if (data != null && data.length() > 0) { + PluginResult result = new PluginResult(PluginResult.Status.OK, data); + result.setKeepCallback(true); + dataAvailableCallback.sendPluginResult(result); + + sendDataToSubscriber(); + } + } + + private int available() { + return buffer.length(); + } + + private String read() { + int length = buffer.length(); + String data = buffer.substring(0, length); + buffer.delete(0, length); + return data; + } + + private String readUntil(String c) { + String data = ""; + int index = buffer.indexOf(c, 0); + if (index > -1) { + data = buffer.substring(0, index + c.length()); + buffer.delete(0, index + c.length()); + } + return data; + } + + // The Handler that gets information back from the BluetoothSerialService + // Original code used handler for the because it was talking to the UI. + // Consider replacing with normal callbacks + private final Handler mHandler = new Handler() { + + public void handleMessage(Message msg) { + switch (msg.what) { + case MESSAGE_READ: + buffer.append((String)msg.obj); + + if (dataAvailableCallback != null) { + sendDataToSubscriber(); + } + + break; + case MESSAGE_READ_RAW: + if (rawDataAvailableCallback != null) { + byte[] bytes = (byte[]) msg.obj; + sendRawDataToSubscriber(bytes); + } + break; + case MESSAGE_STATE_CHANGE: + + if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); + switch (msg.arg1) { + case BluetoothSerialService.STATE_CONNECTED: + Log.i(TAG, "BluetoothSerialService.STATE_CONNECTED"); + notifyConnectionSuccess(); + break; + case BluetoothSerialService.STATE_CONNECTING: + Log.i(TAG, "BluetoothSerialService.STATE_CONNECTING"); + break; + case BluetoothSerialService.STATE_LISTEN: + Log.i(TAG, "BluetoothSerialService.STATE_LISTEN"); + break; + case BluetoothSerialService.STATE_NONE: + Log.i(TAG, "BluetoothSerialService.STATE_NONE"); + break; + } + break; + case MESSAGE_WRITE: + // byte[] writeBuf = (byte[]) msg.obj; + // String writeMessage = new String(writeBuf); + // Log.i(TAG, "Wrote: " + writeMessage); + break; + case MESSAGE_DEVICE_NAME: + Log.i(TAG, msg.getData().getString(DEVICE_NAME)); + break; + case MESSAGE_TOAST: + String message = msg.getData().getString(TOAST); + notifyConnectionLost(message); + break; + } + } + }; + } + + // actions + private static final String LIST = "list"; + private static final String CONNECT = "connect"; + private static final String CONNECT_INSECURE = "connectInsecure"; + private static final String DISCONNECT = "disconnect"; + private static final String WRITE = "write"; + private static final String AVAILABLE = "available"; + private static final String READ = "read"; + private static final String READ_UNTIL = "readUntil"; + private static final String SUBSCRIBE = "subscribe"; + private static final String UNSUBSCRIBE = "unsubscribe"; + private static final String SUBSCRIBE_RAW = "subscribeRaw"; + private static final String UNSUBSCRIBE_RAW = "unsubscribeRaw"; + private static final String IS_ENABLED = "isEnabled"; + private static final String IS_CONNECTED = "isConnected"; + private static final String CLEAR = "clear"; + private static final String SETTINGS = "showBluetoothSettings"; + private static final String ENABLE = "enable"; + private static final String DISCOVER_UNPAIRED = "discoverUnpaired"; + private static final String SET_DEVICE_DISCOVERED_LISTENER = "setDeviceDiscoveredListener"; + private static final String CLEAR_DEVICE_DISCOVERED_LISTENER = "clearDeviceDiscoveredListener"; + private static final String SET_NAME = "setName"; + private static final String SET_DISCOVERABLE = "setDiscoverable"; + + + private BluetoothAdapter bluetoothAdapter; + private HashMap connections = new HashMap(); + String defaultMac=""; + + + // callbacks + public CallbackContext enableBluetoothCallback; + public CallbackContext deviceDiscoveredCallback; + + // Debugging + private static final String TAG = "BluetoothSerial"; + private static final boolean D = true; + + // Message types sent from the BluetoothSerialService Handler + public static final int MESSAGE_STATE_CHANGE = 1; + public static final int MESSAGE_READ = 2; + public static final int MESSAGE_WRITE = 3; + public static final int MESSAGE_DEVICE_NAME = 4; + public static final int MESSAGE_TOAST = 5; + public static final int MESSAGE_READ_RAW = 6; + + // Key names received from the BluetoothChatService Handler + public static final String DEVICE_NAME = "device_name"; + public static final String TOAST = "toast"; + + private static final int REQUEST_ENABLE_BLUETOOTH = 1; + + @Override + public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException { + + LOG.d(TAG, "action = " + action); + + if (bluetoothAdapter == null) { + bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + } + + ConnectionContext cc=null; + + if(!defaultMac.isEmpty()) + { + cc=connections.get(defaultMac); + } + else + { + //prevent crash if no connect has been called + cc = new ConnectionContext(); + } + + boolean validAction = true; + + if (action.equals(LIST)) { + + listBondedDevices(callbackContext); + + } else if (action.equals(CONNECT)) { + + boolean secure = true; + connect(args, secure, callbackContext); + + } else if (action.equals(CONNECT_INSECURE)) { + + // see Android docs about Insecure RFCOMM http://goo.gl/1mFjZY + boolean secure = false; + connect(args, secure, callbackContext); + + } else if (action.equals(DISCONNECT)) { + if(!args.isNull(0)) + { + cc=connections.get(args.getString(0)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + if(cc!=null) + { + cc.connectCallback = null; + cc.bluetoothSerialService.stop(); + callbackContext.success(); + } + + } else if (action.equals(WRITE)) { + if(!args.isNull(1)) + { + cc=connections.get(args.getString(1)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + + if(cc!=null) { + byte[] data = args.getArrayBuffer(0); + cc.bluetoothSerialService.write(data); + callbackContext.success(); + } + + } else if (action.equals(AVAILABLE)) { + if(!args.isNull(0)) + { + cc=connections.get(args.getString(0)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + + if(cc!=null) { + callbackContext.success(cc.available()); + } + + } else if (action.equals(READ)) { + if(!args.isNull(0)) + { + cc=connections.get(args.getString(0)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + + if(cc!=null) { + callbackContext.success(cc.read()); + } + + } else if (action.equals(READ_UNTIL)) { + if(!args.isNull(1)) + { + cc=connections.get(args.getString(1)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + + if(cc!=null) { + String interesting = args.getString(0); + callbackContext.success(cc.readUntil(interesting)); + } + + } else if (action.equals(SUBSCRIBE)) { + if(!args.isNull(1)) + { + cc=connections.get(args.getString(1)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + + if(cc!=null) { + cc.delimiter = args.getString(0); + cc.dataAvailableCallback = callbackContext; + + PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); + result.setKeepCallback(true); + callbackContext.sendPluginResult(result); + } + + } else if (action.equals(UNSUBSCRIBE)) { + if(!args.isNull(0)) + { + cc=connections.get(args.getString(0)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + + if(cc!=null) { + cc.delimiter = null; + + // send no result, so Cordova won't hold onto the data available callback anymore + PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); + cc.dataAvailableCallback.sendPluginResult(result); + cc.dataAvailableCallback = null; + + callbackContext.success(); + } + + } else if (action.equals(SUBSCRIBE_RAW)) { + if(!args.isNull(0)) + { + cc=connections.get(args.getString(0)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + + if(cc!=null) { + cc.rawDataAvailableCallback = callbackContext; + + PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); + result.setKeepCallback(true); + callbackContext.sendPluginResult(result); + } + + } else if (action.equals(UNSUBSCRIBE_RAW)) { + if(!args.isNull(0)) + { + cc=connections.get(args.getString(0)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + + if(cc!=null) { + cc.rawDataAvailableCallback = null; + + callbackContext.success(); + } + + } else if (action.equals(IS_ENABLED)) { + + if (bluetoothAdapter.isEnabled()) { + callbackContext.success(); + } else { + callbackContext.error("Bluetooth is disabled."); + } + + } else if (action.equals(IS_CONNECTED)) { + if(!args.isNull(0)) + { + cc=connections.get(args.getString(0)); + + } + + if (cc!=null && cc.bluetoothSerialService.getState() == BluetoothSerialService.STATE_CONNECTED) { + callbackContext.success(); + } else { + callbackContext.error("Not connected."); + } + + } else if (action.equals(CLEAR)) { + if(!args.isNull(0)) + { + cc=connections.get(args.getString(0)); + if(cc==null) + { + callbackContext.error("Address " + args.getString(0)+" never used before"); + } + } + + if(cc!=null) { + cc.buffer.setLength(0); + callbackContext.success(); + } + + } else if (action.equals(SETTINGS)) { + + Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS); + cordova.getActivity().startActivity(intent); + callbackContext.success(); + + } else if (action.equals(ENABLE)) { + + enableBluetoothCallback = callbackContext; + Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + cordova.startActivityForResult(this, intent, REQUEST_ENABLE_BLUETOOTH); + + } else if (action.equals(DISCOVER_UNPAIRED)) { + + discoverUnpairedDevices(callbackContext); + + } else if (action.equals(SET_DEVICE_DISCOVERED_LISTENER)) { + + this.deviceDiscoveredCallback = callbackContext; + + } else if (action.equals(CLEAR_DEVICE_DISCOVERED_LISTENER)) { + + this.deviceDiscoveredCallback = null; + + } else if (action.equals(SET_NAME)) { + + String newName = args.getString(0); + bluetoothAdapter.setName(newName); + callbackContext.success(); + + } else if (action.equals(SET_DISCOVERABLE)) { + + int discoverableDuration = args.getInt(0); + Intent discoverIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); + discoverIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, discoverableDuration); + cordova.getActivity().startActivity(discoverIntent); + + } else { + validAction = false; + + } + + return validAction; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + + if (requestCode == REQUEST_ENABLE_BLUETOOTH) { + + if (resultCode == Activity.RESULT_OK) { + Log.d(TAG, "User enabled Bluetooth"); + if (enableBluetoothCallback != null) { + enableBluetoothCallback.success(); + } + } else { + Log.d(TAG, "User did *NOT* enable Bluetooth"); + if (enableBluetoothCallback != null) { + enableBluetoothCallback.error("User did not enable Bluetooth"); + } + } + + enableBluetoothCallback = null; + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + for(ConnectionContext conn : connections.values()) + { + conn.bluetoothSerialService.stop(); + + } + } + + private void listBondedDevices(CallbackContext callbackContext) throws JSONException { + JSONArray deviceList = new JSONArray(); + Set bondedDevices = bluetoothAdapter.getBondedDevices(); + + for (BluetoothDevice device : bondedDevices) { + deviceList.put(deviceToJSON(device)); + } + callbackContext.success(deviceList); + } + + private void discoverUnpairedDevices(final CallbackContext callbackContext) throws JSONException { + + final CallbackContext ddc = deviceDiscoveredCallback; + + final BroadcastReceiver discoverReceiver = new BroadcastReceiver() { + + private JSONArray unpairedDevices = new JSONArray(); + + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (BluetoothDevice.ACTION_FOUND.equals(action)) { + BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + try { + JSONObject o = deviceToJSON(device); + unpairedDevices.put(o); + if (ddc != null) { + PluginResult res = new PluginResult(PluginResult.Status.OK, o); + res.setKeepCallback(true); + ddc.sendPluginResult(res); + } + } catch (JSONException e) { + // This shouldn't happen, log and ignore + Log.e(TAG, "Problem converting device to JSON", e); + } + } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { + callbackContext.success(unpairedDevices); + cordova.getActivity().unregisterReceiver(this); + } + } + }; + + Activity activity = cordova.getActivity(); + activity.registerReceiver(discoverReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND)); + activity.registerReceiver(discoverReceiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)); + bluetoothAdapter.startDiscovery(); + } + + private JSONObject deviceToJSON(BluetoothDevice device) throws JSONException { + JSONObject json = new JSONObject(); + json.put("name", device.getName()); + json.put("address", device.getAddress()); + json.put("id", device.getAddress()); + if (device.getBluetoothClass() != null) { + json.put("class", device.getBluetoothClass().getDeviceClass()); + } + return json; + } + + private void connect(CordovaArgs args, boolean secure, CallbackContext callbackContext) throws JSONException { + String macAddress = args.getString(0); + BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAddress); + defaultMac=macAddress; + if (!connections.containsKey(macAddress)) { + connections.put(macAddress, new ConnectionContext()); + } + ConnectionContext cc=connections.get(macAddress); + + if (device != null) { + cc.connectCallback = callbackContext; + cc.bluetoothSerialService.connect(device, secure); + + PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); + result.setKeepCallback(true); + callbackContext.sendPluginResult(result); + + } else { + callbackContext.error("Could not connect to " + macAddress); + } + } + + + +} diff --git a/www/bluetoothSerial.js b/www/bluetoothSerial.js index 250b8aab..2928e69e 100644 --- a/www/bluetoothSerial.js +++ b/www/bluetoothSerial.js @@ -10,8 +10,9 @@ module.exports = { cordova.exec(success, failure, "BluetoothSerial", "connectInsecure", [macAddress]); }, - disconnect: function (success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "disconnect", []); + disconnect: function (success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "disconnect", [macAddress]); }, // list bound devices @@ -23,28 +24,33 @@ module.exports = { cordova.exec(success, failure, "BluetoothSerial", "isEnabled", []); }, - isConnected: function (success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "isConnected", []); + isConnected: function (success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "isConnected", [macAddress]); }, // the number of bytes of data available to read is passed to the success function - available: function (success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "available", []); + available: function (success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "available", [macAddress]); }, // read all the data in the buffer - read: function (success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "read", []); + read: function (success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "read", [macAddress]); }, // reads the data in the buffer up to and including the delimiter - readUntil: function (delimiter, success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "readUntil", [delimiter]); + readUntil: function (delimiter, success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "readUntil", [delimiter,macAddress]); }, // writes data to the bluetooth serial port // data can be an ArrayBuffer, string, integer array, or Uint8Array - write: function (data, success, failure) { + write: function (data, success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; // convert to ArrayBuffer if (typeof data === 'string') { @@ -56,21 +62,24 @@ module.exports = { data = data.buffer; } - cordova.exec(success, failure, "BluetoothSerial", "write", [data]); + cordova.exec(success, failure, "BluetoothSerial", "write", [data,macAddress]); }, // calls the success callback when new data is available - subscribe: function (delimiter, success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "subscribe", [delimiter]); + subscribe: function (delimiter, success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "subscribe", [delimiter,macAddress]); }, // removes data subscription - unsubscribe: function (success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "unsubscribe", []); + unsubscribe: function (success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "unsubscribe", [macAddress]); }, // calls the success callback when new data is available with an ArrayBuffer - subscribeRawData: function (success, failure) { + subscribeRawData: function (success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; successWrapper = function(data) { // Windows Phone flattens an array of one into a number which @@ -82,22 +91,25 @@ module.exports = { } success(data); }; - cordova.exec(successWrapper, failure, "BluetoothSerial", "subscribeRaw", []); + cordova.exec(successWrapper, failure, "BluetoothSerial", "subscribeRaw", [macAddress]); }, // removes data subscription - unsubscribeRawData: function (success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "unsubscribeRaw", []); + unsubscribeRawData: function (success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "unsubscribeRaw", [macAddress]); }, // clears the data buffer - clear: function (success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "clear", []); + clear: function (success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "clear", [macAddress]); }, // reads the RSSI of the *connected* peripherial - readRSSI: function (success, failure) { - cordova.exec(success, failure, "BluetoothSerial", "readRSSI", []); + readRSSI: function (success, failure,macAddress) { + macAddress = typeof macAddress !== 'undefined' ? macAddress : null; + cordova.exec(success, failure, "BluetoothSerial", "readRSSI", [macAddress]); }, showBluetoothSettings: function (success, failure) {