7 package com.google.appinventor.components.runtime;
23 import android.util.Log;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.HashSet;
28 import java.util.List;
30 import java.util.UUID;
40 @DesignerComponent(version = YaVersion.BLUETOOTHCLIENT_COMPONENT_VERSION,
41 description =
"Bluetooth client component",
42 category = ComponentCategory.CONNECTIVITY,
44 iconName =
"images/bluetooth.png")
46 @UsesPermissions(permissionNames =
47 "android.permission.BLUETOOTH, " +
48 "android.permission.BLUETOOTH_ADMIN")
50 private static final String SPP_UUID =
"00001101-0000-1000-8000-00805F9B34FB";
52 private final List<Component> attachedComponents =
new ArrayList<Component>();
53 private Set<Integer> acceptableDeviceClasses;
59 super(container,
"BluetoothClient");
60 DisconnectOnError(
false);
67 description =
"Disconnects BluetoothClient automatically when an error occurs.")
68 public
boolean DisconnectOnError() {
69 return disconnectOnError;
78 defaultValue =
"False")
81 this.disconnectOnError = disconnectOnError;
84 boolean attachComponent(
Component component, Set<Integer> acceptableDeviceClasses) {
85 if (attachedComponents.isEmpty()) {
87 this.acceptableDeviceClasses = (acceptableDeviceClasses ==
null)
89 :
new HashSet<Integer>(acceptableDeviceClasses);
94 if (this.acceptableDeviceClasses ==
null) {
95 if (acceptableDeviceClasses !=
null) {
99 if (acceptableDeviceClasses ==
null) {
102 if (!this.acceptableDeviceClasses.containsAll(acceptableDeviceClasses)) {
105 if (!acceptableDeviceClasses.containsAll(
this.acceptableDeviceClasses)) {
111 attachedComponents.add(component);
115 void detachComponent(Component component) {
116 attachedComponents.remove(component);
117 if (attachedComponents.isEmpty()) {
118 acceptableDeviceClasses =
null;
128 @SimpleFunction(description =
"Checks whether the Bluetooth device with the specified address " +
130 public
boolean IsDevicePaired(String address) {
131 String functionName =
"IsDevicePaired";
133 if (bluetoothAdapter ==
null) {
134 form.dispatchErrorOccurredEvent(
this, functionName,
140 form.dispatchErrorOccurredEvent(
this, functionName,
147 int firstSpace = address.indexOf(
" ");
148 if (firstSpace != -1) {
149 address = address.substring(0, firstSpace);
153 form.dispatchErrorOccurredEvent(
this, functionName,
174 @
SimpleProperty(description =
"The addresses and names of paired Bluetooth devices",
176 public List<String> AddressesAndNames() {
177 List<String> addressesAndNames =
new ArrayList<String>();
180 if (bluetoothAdapter !=
null) {
183 if (isDeviceClassAcceptable(bluetoothDevice)) {
186 addressesAndNames.add(address +
" " + name);
192 return addressesAndNames;
200 private boolean isDeviceClassAcceptable(Object bluetoothDevice) {
201 if (acceptableDeviceClasses ==
null) {
206 Object bluetoothClass = BluetoothReflection.getBluetoothClass(bluetoothDevice);
207 if (bluetoothClass ==
null) {
212 int deviceClass = BluetoothReflection.getDeviceClass(bluetoothClass);
213 return acceptableDeviceClasses.contains(deviceClass);
222 @SimpleFunction(description =
"Connect to the Bluetooth device with the specified address and " +
223 "the Serial Port Profile (SPP). Returns true if the connection was successful.")
224 public
boolean Connect(String address) {
225 return connect(
"Connect", address, SPP_UUID);
235 @
SimpleFunction(description =
"Connect to the Bluetooth device with the specified address and " +
236 "UUID. Returns true if the connection was successful.")
237 public
boolean ConnectWithUUID(String address, String uuid) {
238 return connect(
"ConnectWithUUID", address, uuid);
252 private boolean connect(String functionName, String address, String uuidString) {
254 if (bluetoothAdapter ==
null) {
255 form.dispatchErrorOccurredEvent(
this, functionName,
260 if (!BluetoothReflection.isBluetoothEnabled(bluetoothAdapter)) {
261 form.dispatchErrorOccurredEvent(
this, functionName,
262 ErrorMessages.ERROR_BLUETOOTH_NOT_ENABLED);
268 int firstSpace = address.indexOf(
" ");
269 if (firstSpace != -1) {
270 address = address.substring(0, firstSpace);
273 if (!BluetoothReflection.checkBluetoothAddress(bluetoothAdapter, address)) {
274 form.dispatchErrorOccurredEvent(
this, functionName,
275 ErrorMessages.ERROR_BLUETOOTH_INVALID_ADDRESS);
279 Object bluetoothDevice = BluetoothReflection.getRemoteDevice(bluetoothAdapter, address);
280 if (!BluetoothReflection.isBonded(bluetoothDevice)) {
281 form.dispatchErrorOccurredEvent(
this, functionName,
282 ErrorMessages.ERROR_BLUETOOTH_NOT_PAIRED_DEVICE);
286 if (!isDeviceClassAcceptable(bluetoothDevice)) {
287 form.dispatchErrorOccurredEvent(
this, functionName,
288 ErrorMessages.ERROR_BLUETOOTH_NOT_REQUIRED_CLASS_OF_DEVICE);
294 uuid = UUID.fromString(uuidString);
295 }
catch (IllegalArgumentException e) {
296 form.dispatchErrorOccurredEvent(
this, functionName,
297 ErrorMessages.ERROR_BLUETOOTH_INVALID_UUID, uuidString);
304 connect(bluetoothDevice, uuid);
306 }
catch (IOException e) {
308 form.dispatchErrorOccurredEvent(
this, functionName,
309 ErrorMessages.ERROR_BLUETOOTH_UNABLE_TO_CONNECT);
314 private void connect(Object bluetoothDevice, UUID uuid)
throws IOException {
315 Object bluetoothSocket;
316 if (!secure && SdkLevel.getLevel() >= SdkLevel.LEVEL_GINGERBREAD_MR1) {
318 bluetoothSocket = BluetoothReflection.createInsecureRfcommSocketToServiceRecord(
319 bluetoothDevice, uuid);
321 bluetoothSocket = BluetoothReflection.createRfcommSocketToServiceRecord(
322 bluetoothDevice, uuid);
324 BluetoothReflection.connectToBluetoothSocket(bluetoothSocket);
325 setConnection(bluetoothSocket);
326 Log.i(logTag,
"Connected to Bluetooth device " +
327 BluetoothReflection.getBluetoothDeviceAddress(bluetoothDevice) +
" " +
328 BluetoothReflection.getBluetoothDeviceName(bluetoothDevice) +
".");