AI2 Component  (Version nb184)
BluetoothClient.java
Go to the documentation of this file.
1 // -*- mode: java; c-basic-offset: 2; -*-
2 // Copyright 2009-2011 Google, All Rights reserved
3 // Copyright 2011-2012 MIT, All rights reserved
4 // Released under the Apache License, Version 2.0
5 // http://www.apache.org/licenses/LICENSE-2.0
6 
7 package com.google.appinventor.components.runtime;
8 
22 
23 import android.util.Log;
24 
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Set;
30 import java.util.UUID;
31 
40 @DesignerComponent(version = YaVersion.BLUETOOTHCLIENT_COMPONENT_VERSION,
41  description = "Bluetooth client component",
42  category = ComponentCategory.CONNECTIVITY,
43  nonVisible = true,
44  iconName = "images/bluetooth.png")
45 @SimpleObject
46 @UsesPermissions(permissionNames =
47  "android.permission.BLUETOOTH, " +
48  "android.permission.BLUETOOTH_ADMIN")
49 public final class BluetoothClient extends BluetoothConnectionBase {
50  private static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
51 
52  private final List<Component> attachedComponents = new ArrayList<Component>();
53  private Set<Integer> acceptableDeviceClasses;
54 
58  public BluetoothClient(ComponentContainer container) {
59  super(container, "BluetoothClient");
60  DisconnectOnError(false);
61  }
62 
67  description = "Disconnects BluetoothClient automatically when an error occurs.")
68  public boolean DisconnectOnError() {
69  return disconnectOnError;
70  }
71 
78  defaultValue = "False")
80  public void DisconnectOnError(boolean disconnectOnError) {
81  this.disconnectOnError = disconnectOnError;
82  }
83 
84  boolean attachComponent(Component component, Set<Integer> acceptableDeviceClasses) {
85  if (attachedComponents.isEmpty()) {
86  // If this is the first/only attached component, we keep the acceptableDeviceClasses.
87  this.acceptableDeviceClasses = (acceptableDeviceClasses == null)
88  ? null
89  : new HashSet<Integer>(acceptableDeviceClasses);
90 
91  } else {
92  // If there is already one or more attached components, the acceptableDeviceClasses must be
93  // the same as what we already have.
94  if (this.acceptableDeviceClasses == null) {
95  if (acceptableDeviceClasses != null) {
96  return false;
97  }
98  } else {
99  if (acceptableDeviceClasses == null) {
100  return false;
101  }
102  if (!this.acceptableDeviceClasses.containsAll(acceptableDeviceClasses)) {
103  return false;
104  }
105  if (!acceptableDeviceClasses.containsAll(this.acceptableDeviceClasses)) {
106  return false;
107  }
108  }
109  }
110 
111  attachedComponents.add(component);
112  return true;
113  }
114 
115  void detachComponent(Component component) {
116  attachedComponents.remove(component);
117  if (attachedComponents.isEmpty()) {
118  acceptableDeviceClasses = null;
119  }
120  }
121 
128  @SimpleFunction(description = "Checks whether the Bluetooth device with the specified address " +
129  "is paired.")
130  public boolean IsDevicePaired(String address) {
131  String functionName = "IsDevicePaired";
132  Object bluetoothAdapter = BluetoothReflection.getBluetoothAdapter();
133  if (bluetoothAdapter == null) {
134  form.dispatchErrorOccurredEvent(this, functionName,
136  return false;
137  }
138 
139  if (!BluetoothReflection.isBluetoothEnabled(bluetoothAdapter)) {
140  form.dispatchErrorOccurredEvent(this, functionName,
142  return false;
143  }
144 
145  // Truncate the address at the first space.
146  // This allows the address to be an element from the AddressesAndNames property.
147  int firstSpace = address.indexOf(" ");
148  if (firstSpace != -1) {
149  address = address.substring(0, firstSpace);
150  }
151 
152  if (!BluetoothReflection.checkBluetoothAddress(bluetoothAdapter, address)) {
153  form.dispatchErrorOccurredEvent(this, functionName,
155  return false;
156  }
157 
158  Object bluetoothDevice = BluetoothReflection.getRemoteDevice(bluetoothAdapter, address);
159  return BluetoothReflection.isBonded(bluetoothDevice);
160  }
161 
174  @SimpleProperty(description = "The addresses and names of paired Bluetooth devices",
175  category = PropertyCategory.BEHAVIOR)
176  public List<String> AddressesAndNames() {
177  List<String> addressesAndNames = new ArrayList<String>();
178 
179  Object bluetoothAdapter = BluetoothReflection.getBluetoothAdapter();
180  if (bluetoothAdapter != null) {
181  if (BluetoothReflection.isBluetoothEnabled(bluetoothAdapter)) {
182  for (Object bluetoothDevice : BluetoothReflection.getBondedDevices(bluetoothAdapter)) {
183  if (isDeviceClassAcceptable(bluetoothDevice)) {
184  String name = BluetoothReflection.getBluetoothDeviceName(bluetoothDevice);
185  String address = BluetoothReflection.getBluetoothDeviceAddress(bluetoothDevice);
186  addressesAndNames.add(address + " " + name);
187  }
188  }
189  }
190  }
191 
192  return addressesAndNames;
193  }
194 
200  private boolean isDeviceClassAcceptable(Object bluetoothDevice) {
201  if (acceptableDeviceClasses == null) {
202  // Add devices are acceptable.
203  return true;
204  }
205 
206  Object bluetoothClass = BluetoothReflection.getBluetoothClass(bluetoothDevice);
207  if (bluetoothClass == null) {
208  // This device has no class.
209  return false;
210  }
211 
212  int deviceClass = BluetoothReflection.getDeviceClass(bluetoothClass);
213  return acceptableDeviceClasses.contains(deviceClass);
214  }
215 
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);
226  }
227 
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);
239  }
240 
252  private boolean connect(String functionName, String address, String uuidString) {
253  Object bluetoothAdapter = BluetoothReflection.getBluetoothAdapter();
254  if (bluetoothAdapter == null) {
255  form.dispatchErrorOccurredEvent(this, functionName,
257  return false;
258  }
259 
260  if (!BluetoothReflection.isBluetoothEnabled(bluetoothAdapter)) {
261  form.dispatchErrorOccurredEvent(this, functionName,
262  ErrorMessages.ERROR_BLUETOOTH_NOT_ENABLED);
263  return false;
264  }
265 
266  // Truncate the address at the first space.
267  // This allows the address to be an element from the AddressesAndNames property.
268  int firstSpace = address.indexOf(" ");
269  if (firstSpace != -1) {
270  address = address.substring(0, firstSpace);
271  }
272 
273  if (!BluetoothReflection.checkBluetoothAddress(bluetoothAdapter, address)) {
274  form.dispatchErrorOccurredEvent(this, functionName,
275  ErrorMessages.ERROR_BLUETOOTH_INVALID_ADDRESS);
276  return false;
277  }
278 
279  Object bluetoothDevice = BluetoothReflection.getRemoteDevice(bluetoothAdapter, address);
280  if (!BluetoothReflection.isBonded(bluetoothDevice)) {
281  form.dispatchErrorOccurredEvent(this, functionName,
282  ErrorMessages.ERROR_BLUETOOTH_NOT_PAIRED_DEVICE);
283  return false;
284  }
285 
286  if (!isDeviceClassAcceptable(bluetoothDevice)) {
287  form.dispatchErrorOccurredEvent(this, functionName,
288  ErrorMessages.ERROR_BLUETOOTH_NOT_REQUIRED_CLASS_OF_DEVICE);
289  return false;
290  }
291 
292  UUID uuid;
293  try {
294  uuid = UUID.fromString(uuidString);
295  } catch (IllegalArgumentException e) {
296  form.dispatchErrorOccurredEvent(this, functionName,
297  ErrorMessages.ERROR_BLUETOOTH_INVALID_UUID, uuidString);
298  return false;
299  }
300 
301  Disconnect();
302 
303  try {
304  connect(bluetoothDevice, uuid);
305  return true;
306  } catch (IOException e) {
307  Disconnect();
308  form.dispatchErrorOccurredEvent(this, functionName,
309  ErrorMessages.ERROR_BLUETOOTH_UNABLE_TO_CONNECT);
310  return false;
311  }
312  }
313 
314  private void connect(Object bluetoothDevice, UUID uuid) throws IOException {
315  Object bluetoothSocket;
316  if (!secure && SdkLevel.getLevel() >= SdkLevel.LEVEL_GINGERBREAD_MR1) {
317  // createInsecureRfcommSocketToServiceRecord was introduced in level 10
318  bluetoothSocket = BluetoothReflection.createInsecureRfcommSocketToServiceRecord(
319  bluetoothDevice, uuid);
320  } else {
321  bluetoothSocket = BluetoothReflection.createRfcommSocketToServiceRecord(
322  bluetoothDevice, uuid);
323  }
324  BluetoothReflection.connectToBluetoothSocket(bluetoothSocket);
325  setConnection(bluetoothSocket);
326  Log.i(logTag, "Connected to Bluetooth device " +
327  BluetoothReflection.getBluetoothDeviceAddress(bluetoothDevice) + " " +
328  BluetoothReflection.getBluetoothDeviceName(bluetoothDevice) + ".");
329  }
330 }
com.google.appinventor.components.runtime.util.BluetoothReflection.getBluetoothDeviceAddress
static String getBluetoothDeviceAddress(Object bluetoothDevice)
Definition: BluetoothReflection.java:171
com.google.appinventor.components.annotations.SimpleFunction
Definition: SimpleFunction.java:23
com.google.appinventor.components.runtime.util.ErrorMessages
Definition: ErrorMessages.java:17
com.google.appinventor.components.runtime.util
-*- mode: java; c-basic-offset: 2; -*-
Definition: AccountChooser.java:7
com.google.appinventor.components.runtime.BluetoothClient.BluetoothClient
BluetoothClient(ComponentContainer container)
Definition: BluetoothClient.java:58
com.google.appinventor.components.runtime.util.ErrorMessages.ERROR_BLUETOOTH_NOT_ENABLED
static final int ERROR_BLUETOOTH_NOT_ENABLED
Definition: ErrorMessages.java:71
com.google.appinventor.components.common.YaVersion
Definition: YaVersion.java:14
com.google.appinventor.components.annotations.DesignerProperty
Definition: DesignerProperty.java:25
com.google.appinventor.components.runtime.BluetoothClient.DisconnectOnError
void DisconnectOnError(boolean disconnectOnError)
Definition: BluetoothClient.java:80
com.google.appinventor.components.runtime.util.BluetoothReflection.getBluetoothAdapter
static Object getBluetoothAdapter()
Definition: BluetoothReflection.java:44
com.google.appinventor.components
com.google.appinventor.components.runtime.util.BluetoothReflection
Definition: BluetoothReflection.java:29
com.google.appinventor.components.runtime.util.BluetoothReflection.isBonded
static boolean isBonded(Object bluetoothDevice)
Definition: BluetoothReflection.java:184
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN
static final String PROPERTY_TYPE_BOOLEAN
Definition: PropertyTypeConstants.java:35
com.google.appinventor.components.annotations.DesignerComponent
Definition: DesignerComponent.java:22
com.google.appinventor.components.annotations.PropertyCategory.BEHAVIOR
BEHAVIOR
Definition: PropertyCategory.java:15
com.google.appinventor.components.runtime.util.BluetoothReflection.getRemoteDevice
static Object getRemoteDevice(Object bluetoothAdapter, String address)
Definition: BluetoothReflection.java:105
com.google.appinventor.components.annotations.UsesPermissions
Definition: UsesPermissions.java:21
com.google.appinventor.components.runtime.util.SdkLevel
Definition: SdkLevel.java:19
com.google.appinventor.components.runtime.BluetoothClient
Definition: BluetoothClient.java:49
com.google.appinventor.components.runtime.util.ErrorMessages.ERROR_BLUETOOTH_NOT_AVAILABLE
static final int ERROR_BLUETOOTH_NOT_AVAILABLE
Definition: ErrorMessages.java:70
com.google.appinventor.components.annotations.SimpleProperty
Definition: SimpleProperty.java:23
com.google.appinventor.components.runtime.BluetoothConnectionBase
Definition: BluetoothConnectionBase.java:41
com.google.appinventor.components.annotations.PropertyCategory
Definition: PropertyCategory.java:13
com.google.appinventor.components.runtime.ComponentContainer
Definition: ComponentContainer.java:16
com.google.appinventor.components.runtime.util.BluetoothReflection.isBluetoothEnabled
static boolean isBluetoothEnabled(Object bluetoothAdapter)
Definition: BluetoothReflection.java:63
com.google.appinventor.components.runtime
Copyright 2009-2011 Google, All Rights reserved.
Definition: AccelerometerSensor.java:8
com.google.appinventor.components.runtime.Component
Definition: Component.java:17
com.google.appinventor.components.runtime.util.BluetoothReflection.checkBluetoothAddress
static boolean checkBluetoothAddress(Object bluetoothAdapter, String address)
Definition: BluetoothReflection.java:90
com.google.appinventor.components.runtime.util.ErrorMessages.ERROR_BLUETOOTH_INVALID_ADDRESS
static final int ERROR_BLUETOOTH_INVALID_ADDRESS
Definition: ErrorMessages.java:72
com.google.appinventor.components.common
Definition: ComponentCategory.java:7
com.google.appinventor.components.common.ComponentCategory
Definition: ComponentCategory.java:48
com.google.appinventor.components.annotations.SimpleObject
Definition: SimpleObject.java:23
com.google
com
com.google.appinventor.components.runtime.util.BluetoothReflection.getBondedDevices
static Set getBondedDevices(Object bluetoothAdapter)
Definition: BluetoothReflection.java:76
com.google.appinventor.components.runtime.util.BluetoothReflection.getBluetoothDeviceName
static String getBluetoothDeviceName(Object bluetoothDevice)
Definition: BluetoothReflection.java:158
com.google.appinventor.components.common.PropertyTypeConstants
Definition: PropertyTypeConstants.java:14
com.google.appinventor.components.annotations
com.google.appinventor