7 package com.google.appinventor.components.runtime;
21 import android.util.Log;
23 import java.io.BufferedInputStream;
24 import java.io.BufferedOutputStream;
25 import java.io.ByteArrayOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.OutputStream;
29 import java.io.UnsupportedEncodingException;
30 import java.nio.ByteOrder;
31 import java.util.ArrayList;
32 import java.util.List;
45 private final List<BluetoothConnectionListener> bluetoothConnectionListeners =
46 new ArrayList<BluetoothConnectionListener>();
48 private ByteOrder byteOrder;
49 private String encoding;
50 private byte delimiter;
54 private Object connectedBluetoothSocket;
55 private InputStream inputStream;
56 private OutputStream outputStream;
57 private final int sdkLevel;
70 this.sdkLevel = sdkLevel;
71 this.disconnectOnError =
false;
84 this.connectedBluetoothSocket =
"Not Null";
85 this.outputStream = outputStream;
86 this.inputStream = inputStream;
94 void addBluetoothConnectionListener(BluetoothConnectionListener listener) {
95 bluetoothConnectionListeners.add(listener);
103 void removeBluetoothConnectionListener(BluetoothConnectionListener listener) {
104 bluetoothConnectionListeners.remove(listener);
107 private void fireAfterConnectEvent() {
108 for (BluetoothConnectionListener listener : bluetoothConnectionListeners) {
109 listener.afterConnect(
this);
113 private void fireBeforeDisconnectEvent() {
114 for (BluetoothConnectionListener listener : bluetoothConnectionListeners) {
115 listener.beforeDisconnect(
this);
125 @
SimpleEvent(description =
"The BluetoothError event is no longer used. " +
126 "Please use the Screen.ErrorOccurred event instead.",
131 protected void bluetoothError(String functionName,
int errorNumber, Object... messageArgs) {
141 @
SimpleProperty(description =
"Whether Bluetooth is available on the device",
145 if (bluetoothAdapter !=
null) {
160 if (bluetoothAdapter !=
null) {
168 protected final void setConnection(Object bluetoothSocket)
throws IOException {
169 connectedBluetoothSocket = bluetoothSocket;
170 inputStream =
new BufferedInputStream(
172 outputStream =
new BufferedOutputStream(
174 fireAfterConnectEvent();
180 @
SimpleFunction(description =
"Disconnect from the connected Bluetooth device.")
182 if (connectedBluetoothSocket !=
null) {
183 fireBeforeDisconnectEvent();
186 Log.i(
logTag,
"Disconnected from Bluetooth device.");
187 }
catch (IOException e) {
188 Log.w(
logTag,
"Error while disconnecting: " + e.getMessage());
190 connectedBluetoothSocket =
null;
200 description =
"On devices with API level 14 (LEVEL_ICE_CREAM_SANDWICH) or higher, " +
201 "this property returned is accurate. But on old devices with API level lower than 14, " +
202 "it may not return the current state of connection(e.g., it might be disconnected but you " +
203 "may not know until you attempt to read/write the socket.")
208 return (connectedBluetoothSocket !=
null);
223 description =
"Whether to invoke SSP (Simple Secure Pairing), which is supported on " +
224 "devices with Bluetooth v2.1 or higher. When working with embedded Bluetooth devices, " +
225 "this property may need to be set to False. For Android 2.0-2.2, this property setting " +
237 defaultValue =
"True")
253 return byteOrder == ByteOrder.BIG_ENDIAN;
264 defaultValue =
"False")
267 byteOrder = highByteFirst ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
279 "check".getBytes(encoding);
280 this.encoding = encoding;
281 }
catch (UnsupportedEncodingException e) {
306 String functionName =
"DelimiterByte";
310 if (n != 0 && n != -1) {
333 @
SimpleFunction(description =
"Send text to the connected Bluetooth device.")
337 bytes = text.getBytes(encoding);
338 }
catch (UnsupportedEncodingException e) {
339 Log.w(
logTag,
"UnsupportedEncodingException: " + e.getMessage());
340 bytes = text.getBytes();
342 write(
"SendText", bytes);
359 @
SimpleFunction(description =
"Send a 1-byte number to the connected Bluetooth device.")
361 String functionName =
"Send1ByteNumber";
364 n = Integer.decode(number);
365 }
catch (NumberFormatException e) {
372 if (n != 0 && n != -1) {
377 write(functionName, b);
390 @
SimpleFunction(description =
"Send a 2-byte number to the connected Bluetooth device.")
392 String functionName =
"Send2ByteNumber";
395 n = Integer.decode(number);
396 }
catch (NumberFormatException e) {
401 byte[] bytes =
new byte[2];
402 if (byteOrder == ByteOrder.BIG_ENDIAN) {
403 bytes[1] = (byte) (n & 0xFF);
405 bytes[0] = (byte) (n & 0xFF);
407 bytes[0] = (byte) (n & 0xFF);
409 bytes[1] = (byte) (n & 0xFF);
412 if (n != 0 && n != -1) {
417 write(functionName, bytes);
430 @
SimpleFunction(description =
"Send a 4-byte number to the connected Bluetooth device.")
432 String functionName =
"Send4ByteNumber";
435 n = Long.decode(number);
436 }
catch (NumberFormatException e) {
441 byte[] bytes =
new byte[4];
442 if (byteOrder == ByteOrder.BIG_ENDIAN) {
443 bytes[3] = (byte) (n & 0xFF);
445 bytes[2] = (byte) (n & 0xFF);
447 bytes[1] = (byte) (n & 0xFF);
449 bytes[0] = (byte) (n & 0xFF);
451 bytes[0] = (byte) (n & 0xFF);
453 bytes[1] = (byte) (n & 0xFF);
455 bytes[2] = (byte) (n & 0xFF);
457 bytes[3] = (byte) (n & 0xFF);
460 if (n != 0 && n != -1) {
465 write(functionName, bytes);
478 @
SimpleFunction(description =
"Send a list of byte values to the connected Bluetooth device.")
480 String functionName =
"SendBytes";
481 Object[] array = list.toArray();
482 byte[] bytes =
new byte[array.length];
483 for (
int i = 0; i < array.length; i++) {
486 Object element = array[i];
487 String s = element.toString();
490 n = Integer.decode(s);
491 }
catch (NumberFormatException e) {
496 bytes[i] = (byte) (n & 0xFF);
498 if (n != 0 && n != -1) {
504 write(functionName, bytes);
513 protected void write(String functionName,
byte b) {
521 outputStream.write(b);
522 outputStream.flush();
523 }
catch (IOException e) {
524 Log.e(
logTag,
"IO Exception during Writing" + e.getMessage());
539 protected void write(String functionName,
byte[] bytes) {
547 outputStream.write(bytes);
548 outputStream.flush();
549 }
catch (IOException e) {
550 Log.e(
logTag,
"IO Exception during Writing" + e.getMessage());
562 @
SimpleFunction(description =
"Returns an estimate of the number of bytes that can be " +
563 "received without blocking")
565 String functionName =
"BytesAvailableToReceive";
573 return inputStream.available();
574 }
catch (IOException e) {
575 Log.e(
logTag,
"IO Exception during Getting Receive Availability " + e.getMessage());
593 @
SimpleFunction(description =
"Receive text from the connected Bluetooth device. " +
594 "If numberOfBytes is less than 0, read until a delimiter byte value is received.")
596 byte[] bytes =
read(
"ReceiveText", numberOfBytes);
598 if (numberOfBytes < 0) {
600 return new String(bytes, 0, bytes.length - 1, encoding);
602 return new String(bytes, encoding);
604 }
catch (UnsupportedEncodingException e) {
605 Log.w(
logTag,
"UnsupportedEncodingException: " + e.getMessage());
606 return new String(bytes);
613 @
SimpleFunction(description =
"Receive a signed 1-byte number from the connected " +
616 byte[] bytes =
read(
"ReceiveSigned1ByteNumber", 1);
617 if (bytes.length != 1) {
627 @
SimpleFunction(description =
"Receive an unsigned 1-byte number from the connected " +
630 byte[] bytes =
read(
"ReceiveUnsigned1ByteNumber", 1);
631 if (bytes.length != 1) {
635 return bytes[0] & 0xFF;
641 @
SimpleFunction(description =
"Receive a signed 2-byte number from the connected " +
644 byte[] bytes =
read(
"ReceiveSigned2ByteNumber", 2);
645 if (bytes.length != 2) {
649 if (byteOrder == ByteOrder.BIG_ENDIAN) {
650 return (bytes[1] & 0xFF) | (bytes[0] << 8);
652 return (bytes[0] & 0xFF) | (bytes[1] << 8);
659 @
SimpleFunction(description =
"Receive a unsigned 2-byte number from the connected " +
662 byte[] bytes =
read(
"ReceiveUnsigned2ByteNumber", 2);
663 if (bytes.length != 2) {
667 if (byteOrder == ByteOrder.BIG_ENDIAN) {
668 return (bytes[1] & 0xFF) | ((bytes[0] & 0xFF) << 8);
670 return (bytes[0] & 0xFF) | ((bytes[1] & 0xFF) << 8);
677 @
SimpleFunction(description =
"Receive a signed 4-byte number from the connected " +
680 byte[] bytes =
read(
"ReceiveSigned4ByteNumber", 4);
681 if (bytes.length != 4) {
685 if (byteOrder == ByteOrder.BIG_ENDIAN) {
686 return (bytes[3] & 0xFF) |
687 ((bytes[2] & 0xFF) << 8) |
688 ((bytes[1] & 0xFF) << 16) |
691 return (bytes[0] & 0xFF) |
692 ((bytes[1] & 0xFF) << 8) |
693 ((bytes[2] & 0xFF) << 16) |
701 @
SimpleFunction(description =
"Receive a unsigned 4-byte number from the connected " +
704 byte[] bytes =
read(
"ReceiveUnsigned4ByteNumber", 4);
705 if (bytes.length != 4) {
709 if (byteOrder == ByteOrder.BIG_ENDIAN) {
710 return (bytes[3] & 0xFFL) |
711 ((bytes[2] & 0xFFL) << 8) |
712 ((bytes[1] & 0xFFL) << 16) |
713 ((bytes[0] & 0xFFL) << 24);
715 return (bytes[0] & 0xFFL) |
716 ((bytes[1] & 0xFFL) << 8) |
717 ((bytes[2] & 0xFFL) << 16) |
718 ((bytes[3] & 0xFFL) << 24);
732 @
SimpleFunction(description =
"Receive multiple signed byte values from the connected " +
733 "Bluetooth device. If numberOfBytes is less than 0, read until a delimiter byte value " +
736 byte[] bytes =
read(
"ReceiveSignedBytes", numberOfBytes);
737 List<Integer> list =
new ArrayList<Integer>();
738 for (
int i = 0; i < bytes.length; i++) {
755 @
SimpleFunction(description =
"Receive multiple unsigned byte values from the connected " +
756 "Bluetooth device. If numberOfBytes is less than 0, read until a delimiter byte value " +
759 byte[] bytes =
read(
"ReceiveUnsignedBytes", numberOfBytes);
760 List<Integer> list =
new ArrayList<Integer>();
761 for (
int i = 0; i < bytes.length; i++) {
762 int n = bytes[i] & 0xFF;
778 protected final byte[]
read(String functionName,
int numberOfBytes) {
785 ByteArrayOutputStream buffer =
new ByteArrayOutputStream();
787 if (numberOfBytes >= 0) {
789 byte[] bytes =
new byte[numberOfBytes];
790 int totalBytesRead = 0;
791 while (totalBytesRead < numberOfBytes) {
793 int numBytesRead = inputStream.read(bytes, totalBytesRead, bytes.length - totalBytesRead);
794 if (numBytesRead == -1) {
799 totalBytesRead += numBytesRead;
800 }
catch (IOException e) {
801 Log.e(
logTag,
"IO Exception during Reading " + e.getMessage());
810 buffer.write(bytes, 0, totalBytesRead);
815 int value = inputStream.read();
822 if (value == delimiter) {
825 }
catch (IOException e) {
826 Log.e(
logTag,
"IO Exception during Reading " + e.getMessage());
837 return buffer.toByteArray();
854 private void prepareToDie() {
855 if (connectedBluetoothSocket !=
null) {