blob: 82150563fcf79f1e080678140bc9a3ba25aec7ed [file] [log] [blame]
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.googlecode.android_scripting.bluetooth;
import android.app.Service;
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 com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.MainThread;
import com.googlecode.android_scripting.facade.FacadeManager;
import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
import com.googlecode.android_scripting.rpc.Rpc;
import com.googlecode.android_scripting.rpc.RpcDefault;
import com.googlecode.android_scripting.rpc.RpcMinSdk;
import com.googlecode.android_scripting.rpc.RpcOptional;
import com.googlecode.android_scripting.rpc.RpcParameter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
/**
* Basic Bluetooth functions.
*
*/
@RpcMinSdk(5)
public class BluetoothFacade extends RpcReceiver {
private final Service mService;
private final BroadcastReceiver mDiscoveryReceiver;
private final IntentFilter discoveryFilter;
private Map<String, BluetoothConnection>
connections = new HashMap<String, BluetoothConnection>();
private BluetoothAdapter mBluetoothAdapter;
public static ConcurrentHashMap<String, BluetoothDevice> DiscoveredDevices;
public BluetoothFacade(FacadeManager manager) {
super(manager);
mBluetoothAdapter = MainThread.run(manager.getService(), new Callable<BluetoothAdapter>() {
@Override
public BluetoothAdapter call() throws Exception {
return BluetoothAdapter.getDefaultAdapter();
}
});
mService = manager.getService();
DiscoveredDevices = new ConcurrentHashMap<String, BluetoothDevice>();
discoveryFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
mDiscoveryReceiver = new DiscoveryCacheReceiver();
}
class DiscoveryCacheReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothDevice.ACTION_FOUND)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d("Found device " + device.getAliasName());
if (!DiscoveredDevices.containsKey(device.getAddress())) {
String name = device.getAliasName();
if(name != null) {
DiscoveredDevices.put(device.getAliasName(), device);
}
DiscoveredDevices.put(device.getAddress(), device);
}
}
}
}
public static <T> BluetoothDevice getDevice(ConcurrentHashMap<String, T> devices,
String device)throws Exception {
if(devices.containsKey(device)) {
return (BluetoothDevice) devices.get(device);
}else{
throw new Exception("Can't find device " + device);
}
}
public static BluetoothDevice getDevice(Collection<BluetoothDevice> devices,
String deviceID) throws Exception {
for(BluetoothDevice bd : devices) {
if (deviceID.equals(bd.getAliasName()) || deviceID.equals(bd.getAddress())) {
Log.d("Found match " + bd.getAliasName() + " " + bd.getAddress());
return bd;
}
}
throw new Exception("Can't find device " + deviceID);
}
@Rpc(description = "Requests that the device be discoverable for Bluetooth connections.")
public void bluetoothMakeDiscoverable(
@RpcParameter(name = "duration",
description = "period of time, in seconds, during which the device should be discoverable")
@RpcDefault("300")
Integer duration) {
Log.d("Making discoverable for "+duration+" seconds.\n");
mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, duration);
}
@Rpc(description = "Requests that the device be not discoverable.")
public void bluetoothMakeUndiscoverable() {
Log.d("Making undiscoverable\n");
mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_NONE);
}
@Rpc(description = "Queries a remote device for it's name or null if it can't be resolved")
public String bluetoothGetRemoteDeviceName(
@RpcParameter(name = "address", description = "Bluetooth Address For Target Device")
String address) {
try {
BluetoothDevice mDevice;
mDevice = mBluetoothAdapter.getRemoteDevice(address);
return mDevice.getName();
} catch (Exception e) {
return null;
}
}
@Rpc(description = "Get local Bluetooth device name")
public String bluetoothGetLocalName() {
return mBluetoothAdapter.getName();
}
@Rpc(description = "Returns the hardware address of the local Bluetooth adapter. ")
public String bluetoothGetLocalAddress() {
return mBluetoothAdapter.getAddress();
}
@Rpc(description = "Gets the scan mode for the local dongle.\r\n" + "Return values:\r\n"
+ "\t-1 when Bluetooth is disabled.\r\n" + "\t0 if non discoverable and non connectable.\r\n"
+ "\r1 connectable non discoverable." + "\r3 connectable and discoverable.")
public int bluetoothGetScanMode() {
if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF
|| mBluetoothAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF) {
return -1;
}
switch (mBluetoothAdapter.getScanMode()) {
case BluetoothAdapter.SCAN_MODE_NONE:
return 0;
case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
return 1;
case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
return 3;
default:
return mBluetoothAdapter.getScanMode() - 20;
}
}
@Rpc(description = "Return the set of BluetoothDevice that are paired to the local adapter.")
public Set<BluetoothDevice> bluetoothGetBondedDevices() {
return mBluetoothAdapter.getBondedDevices();
}
@Rpc(description = "Checks Bluetooth state.", returns = "True if Bluetooth is enabled.")
public Boolean bluetoothCheckState() {
return mBluetoothAdapter.isEnabled();
}
@Rpc(description = "Sets the Bluetooth visible device name", returns = "true on success")
public boolean bluetoothSetLocalName(
@RpcParameter(name = "name", description = "New local name") String name) {
return mBluetoothAdapter.setName(name);
}
@Rpc(description = "Toggle Bluetooth on and off.", returns = "True if Bluetooth is enabled.")
public Boolean bluetoothToggleState(
@RpcParameter(name = "enabled") @RpcOptional
Boolean enabled,
@RpcParameter(name = "prompt",
description = "Prompt the user to confirm changing the Bluetooth state.")
@RpcDefault("false")
Boolean prompt
) {
if (enabled == null) {
enabled = !bluetoothCheckState();
}
if (enabled) {
// TODO(damonkohler): Make this synchronous as well.
mBluetoothAdapter.enable();
} else {
// TODO(damonkohler): Add support for prompting on disable.
// TODO(damonkohler): Make this synchronous as well.
shutdown();
mBluetoothAdapter.disable();
}
return enabled;
}
@Rpc(description = "Start the remote device discovery process. ",
returns = "true on success, false on error")
public Boolean bluetoothStartDiscovery() {
mService.registerReceiver(mDiscoveryReceiver, discoveryFilter);
return mBluetoothAdapter.startDiscovery();
}
@Rpc(description = "Cancel the current device discovery process.",
returns = "true on success, false on error")
public Boolean bluetoothCancelDiscovery() {
mService.unregisterReceiver(mDiscoveryReceiver);
return mBluetoothAdapter.cancelDiscovery();
}
@Rpc(description =
"If the local Bluetooth adapter is currently in the device discovery process.")
public Boolean bluetoothIsDiscovering() {
return mBluetoothAdapter.isDiscovering();
}
@Rpc(description = "Get all the discovered bluetooth devices.")
public Collection<BluetoothDevice> bluetoothGetDiscoveredDevices() {
while(bluetoothIsDiscovering());
return DiscoveredDevices.values();
}
@Override
public void shutdown() {
for (Map.Entry<String, BluetoothConnection> entry : connections.entrySet()) {
entry.getValue().stop();
}
connections.clear();
}
}