/**
* BlueCove - Java library for Bluetooth
* Copyright (C) 2008-2009 Michael Lifshits
* Copyright (C) 2008-2009 Vlad Skarzhevskyy
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
* @author vlads
* @version $Id$
*/
package com.intel.bluetooth.emu;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.bluetooth.BluetoothConnectionException;
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.ServiceRegistrationException;
import com.intel.bluetooth.DebugLog;
import com.intel.bluetooth.RemoteDeviceHelper;
public class DeviceManagerServiceImpl implements DeviceManagerService {
public static final int MAJOR_COMPUTER = 0x0100;
static final EmulatorConfiguration configuration;
private static Map<Long, Device> devices = new Hashtable<Long, Device>();
static {
configuration = new EmulatorConfiguration();
configuration.loadConfigFile();
}
public DeviceManagerServiceImpl() {
}
public void shutdown() {
synchronized (devices) {
for (Iterator<Device> iterator = devices.values().iterator(); iterator.hasNext();) {
Device device = iterator.next();
device.release();
}
devices.clear();
}
}
public DeviceDescriptor createNewDevice(String deviceID, String deviceAddress) throws BluetoothStateException {
synchronized (devices) {
long address = getNextAvailableBTAddress(deviceID, deviceAddress);
String name = configuration.getProperty(address, EmulatorConfiguration.deviceName);
if (name == null) {
name = configuration.getDeviceNamePrefix() + RemoteDeviceHelper.getBluetoothAddress(address);
}
int deviceClass = MAJOR_COMPUTER;
String cod = configuration.getProperty(address, EmulatorConfiguration.deviceClass);
if (cod != null) {
deviceClass = EmulatorConfiguration.valueToInt(cod);
}
DeviceDescriptor descriptor = new DeviceDescriptor(address, name, deviceClass);
if (!configuration.isDeviceDiscoverable()) {
descriptor.setDiscoverableMode(DiscoveryAgent.NOT_DISCOVERABLE);
}
devices.put(new Long(address), new Device(descriptor));
return descriptor;
}
}
public EmulatorConfiguration getEmulatorConfiguration(long localAddress) {
return configuration.clone(localAddress);
}
public void releaseDevice(long address) {
Device device;
synchronized (devices) {
device = (Device) devices.remove(new Long(address));
}
if (device != null) {
device.release();
}
}
public DeviceCommand pollCommand(long address) {
Device device = getDevice(address);
if (device == null) {
throw new RuntimeException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
}
return device.pollCommand();
}
static Device getDevice(long address) {
Device d = ((Device) devices.get(new Long(address)));
if ((d != null) && (!d.isAlive())) {
synchronized (devices) {
devices.remove(new Long(address));
}
d.died();
return null;
}
return d;
}
private Device getActiveDevice(long address) {
Device d = getDevice(address);
if ((d != null) && (!d.getDescriptor().isPoweredOn())) {
return null;
} else {
return d;
}
}
public DeviceDescriptor getDeviceDescriptor(long address) {
Device device = getDevice(address);
if (device == null) {
throw new RuntimeException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
}
return device.getDescriptor();
}
private DeviceSDP getDeviceSDP(long address) {
Device device = getActiveDevice(address);
if (device == null) {
return null;
}
return device.getDeviceSDP(false);
}
public static List<MonitorDevice> getMonitorDevices() {
Vector<MonitorDevice> monitorDevices = new Vector<MonitorDevice>();
synchronized (devices) {
for (Iterator<Device> iterator = devices.values().iterator(); iterator.hasNext();) {
Device device = iterator.next();
if (!device.isAlive()) {
iterator.remove();
device.died();
continue;
}
isDiscoverable(device.getDescriptor());
monitorDevices.add(new MonitorDevice(device));
}
}
return monitorDevices;
}
public DeviceDescriptor[] getDiscoveredDevices(long address) {
Vector<DeviceDescriptor> discoveredDevice = new Vector<DeviceDescriptor>();
synchronized (devices) {
for (Iterator<Device> iterator = devices.values().iterator(); iterator.hasNext();) {
Device device = iterator.next();
if (!device.isAlive()) {
iterator.remove();
device.died();
continue;
}
if (device.getDescriptor().getAddress() == address) {
continue;
}
if (isDiscoverable(device.getDescriptor())) {
discoveredDevice.addElement(device.getDescriptor());
}
}
}
return (DeviceDescriptor[]) discoveredDevice.toArray(new DeviceDescriptor[discoveredDevice.size()]);
}
private static boolean isDiscoverable(DeviceDescriptor device) {
if (!device.isPoweredOn()) {
return false;
}
int discoverableMode = device.getDiscoverableMode();
switch (discoverableMode) {
case DiscoveryAgent.NOT_DISCOVERABLE:
return false;
case DiscoveryAgent.GIAC:
return true;
case DiscoveryAgent.LIAC:
if (device.getLimitedDiscoverableStart() + configuration.getDurationLIAC() * 1000 * 60 < System
.currentTimeMillis()) {
DebugLog.debug(RemoteDeviceHelper.getBluetoothAddress(device.getAddress())
+ " LIAC -> NOT_DISCOVERABLE");
device.setDiscoverableMode(DiscoveryAgent.NOT_DISCOVERABLE);
return false;
} else {
return true;
}
default:
// No idea what are other modes are.
return true;
}
}
public boolean isLocalDevicePowerOn(long localAddress) {
return getDeviceDescriptor(localAddress).isPoweredOn();
}
public void setLocalDevicePower(long localAddress, boolean on) {
Device device = getDevice(localAddress);
if (device == null) {
throw new RuntimeException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
}
device.setDevicePower(on);
}
public int getLocalDeviceDiscoverable(long localAddress) {
DeviceDescriptor dd = getDeviceDescriptor(localAddress);
if (!dd.isPoweredOn()) {
return DiscoveryAgent.NOT_DISCOVERABLE;
}
// Update mode if it was LIAC
isDiscoverable(dd);
return dd.getDiscoverableMode();
}
public boolean setLocalDeviceDiscoverable(long localAddress, int mode) throws BluetoothStateException {
DeviceDescriptor dd = getDeviceDescriptor(localAddress);
if (!dd.isPoweredOn()) {
throw new BluetoothStateException("Device power is off");
}
DebugLog.debug(RemoteDeviceHelper.getBluetoothAddress(localAddress) + " setDiscoverableMode", EmulatorUtils
.discoverableModeString(mode));
dd.setDiscoverableMode(mode);
return true;
}
public void setLocalDeviceServiceClasses(long localAddress, int classOfDevice) {
DebugLog.debug(RemoteDeviceHelper.getBluetoothAddress(localAddress) + " setServiceClasses ", classOfDevice);
getDeviceDescriptor(localAddress).setDeviceClass(classOfDevice);
}
public String getRemoteDeviceFriendlyName(long address) throws IOException {
DeviceDescriptor dd = getDeviceDescriptor(address);
if (!dd.isPoweredOn()) {
throw new IOException("Remote device power is off");
}
return dd.getName();
}
private long getNextAvailableBTAddress(String deviceID, String deviceAddress) throws BluetoothStateException {
if (deviceID != null) {
long id = configuration.getFirstDeviceAddress() + Long.parseLong(deviceID);
if (getDevice(id) != null) {
throw new BluetoothStateException("Device already reserved "
+ RemoteDeviceHelper.getBluetoothAddress(id));
}
return id;
} else if (deviceAddress != null) {
long address = RemoteDeviceHelper.getAddress(deviceAddress);
if (getDevice(address) != null) {
throw new BluetoothStateException("Device already reserved "
+ RemoteDeviceHelper.getBluetoothAddress(address));
}
return address;
} else {
return EmulatorUtils.getNextAvailable(devices.keySet(), configuration.getFirstDeviceAddress(), 1);
}
}
public void updateServiceRecord(long address, long handle, ServicesDescriptor sdpData)
throws ServiceRegistrationException {
Device device = getActiveDevice(address);
if (device == null) {
throw new ServiceRegistrationException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
}
DeviceSDP ds = device.getDeviceSDP(true);
ds.updateServiceRecord(handle, sdpData);
}
public void removeServiceRecord(long address, long handle) throws IOException {
DeviceSDP ds = getDeviceSDP(address);
if (ds != null) {
ds.removeServiceRecord(handle);
}
}
public long[] searchServices(long address, String[] uuidSet) {
if (getActiveDevice(address) == null) {
return null;
}
DeviceSDP ds = getDeviceSDP(address);
if (ds == null) {
return new long[0];
}
return ds.searchServices(uuidSet);
}
public byte[] getServicesRecordBinary(long address, long handle) throws IOException {
DeviceSDP ds = getDeviceSDP(address);
if (ds == null) {
throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
}
ServicesDescriptor sd = ds.getServicesDescriptor(handle);
if (sd == null) {
throw new IOException("No such service");
}
return sd.getSdpBinary();
}
public void rfOpenService(long localAddress, int channel) throws IOException {
openService(localAddress, ServiceListener.rfPrefix(channel));
}
public long rfAccept(long localAddress, int channel, boolean authenticate, boolean encrypt) throws IOException {
return accept(localAddress, ServiceListener.rfPrefix(channel), authenticate, encrypt, 0);
}
public long rfConnect(long localAddress, long remoteAddress, int channel, boolean authenticate, boolean encrypt,
int timeout) throws IOException {
return connect(localAddress, remoteAddress, ServiceListener.rfPrefix(channel), authenticate, encrypt, 0,
timeout);
}
public void rfCloseService(long address, int pcm) {
closeService(address, ServiceListener.rfPrefix(pcm));
}
public void l2OpenService(long localAddress, int pcm) throws IOException {
openService(localAddress, ServiceListener.l2Prefix(pcm));
}
public long l2Accept(long localAddress, int channel, boolean authenticate, boolean encrypt, int receiveMTU)
throws IOException {
return accept(localAddress, ServiceListener.l2Prefix(channel), authenticate, encrypt, receiveMTU);
}
public long l2Connect(long localAddress, long remoteAddress, int channel, boolean authenticate, boolean encrypt,
int receiveMTU, int timeout) throws IOException {
return connect(localAddress, remoteAddress, ServiceListener.l2Prefix(channel), authenticate, encrypt,
receiveMTU, timeout);
}
public void l2CloseService(long address, int channel) {
closeService(address, ServiceListener.l2Prefix(channel));
}
private long accept(long localAddress, String channelID, boolean authenticate, boolean encrypt, int receiveMTU)
throws IOException {
Device device;
if ((device = getActiveDevice(localAddress)) == null) {
throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
}
ServiceListener sl = device.createServiceListener(channelID);
return sl.accept(device, authenticate, encrypt, receiveMTU);
}
private long connect(long localAddress, long remoteAddress, String portID, boolean authenticate, boolean encrypt,
int receiveMTU, int timeout) throws IOException {
Device remoteDevice = getActiveDevice(remoteAddress);
if (remoteDevice == null) {
throw new BluetoothConnectionException(BluetoothConnectionException.FAILED_NOINFO, "No such device "
+ RemoteDeviceHelper.getBluetoothAddress(remoteAddress));
}
Device localDevice = getActiveDevice(localAddress);
if (localDevice == null) {
throw new BluetoothConnectionException(BluetoothConnectionException.FAILED_NOINFO, "No such device "
+ RemoteDeviceHelper.getBluetoothAddress(localAddress));
}
if (localDevice.getConnectionBuffer(remoteAddress, portID) != null) {
throw new BluetoothConnectionException(BluetoothConnectionException.FAILED_NOINFO,
"Already connected to the same port " + portID + " on "
+ RemoteDeviceHelper.getBluetoothAddress(remoteAddress));
}
ServiceListener sl = remoteDevice.connectService(portID, timeout);
if (sl == null) {
throw new BluetoothConnectionException(BluetoothConnectionException.UNKNOWN_PSM, "No such service "
+ portID);
}
return sl.connect(localDevice, authenticate, encrypt, receiveMTU, timeout);
}
public void connectionAccepted(long localAddress, long connectionId) throws IOException {
Device device;
if ((device = getActiveDevice(localAddress)) == null) {
throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
}
ConnectionBuffer c = device.getConnectionBuffer(connectionId);
if (c == null) {
throw new IOException("No such connection " + connectionId);
}
c.accepted();
}
private void openService(long address, String channelID) throws IOException {
Device device = getActiveDevice(address);
if (device == null) {
throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
}
device.openService(channelID);
}
private void closeService(long address, String channelID) {
Device device = getDevice(address);
if (device == null) {
return;
}
device.closeService(channelID);
}
private ConnectionBuffer getConnectionBuffer(long localAddress, long connectionId) throws IOException {
Device localDevice = getActiveDevice(localAddress);
if (localDevice == null) {
throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
}
ConnectionBuffer c = localDevice.getConnectionBuffer(connectionId);
if (c == null) {
throw new IOException("No such connection " + connectionId);
}
return c;
}
public long getRemoteAddress(long localAddress, long connectionId) throws IOException {
return getConnectionBuffer(localAddress, connectionId).getRemoteAddress();
}
public void rfWrite(long localAddress, long connectionId, byte[] b) throws IOException {
((ConnectionBufferRFCOMM) getConnectionBuffer(localAddress, connectionId)).rfWrite(b);
}
public void rfFlush(long localAddress, long connectionId) throws IOException {
((ConnectionBufferRFCOMM) getConnectionBuffer(localAddress, connectionId)).rfFlush();
}
public int rfAvailable(long localAddress, long connectionId) throws IOException {
return ((ConnectionBufferRFCOMM) getConnectionBuffer(localAddress, connectionId)).rfAvailable();
}
public byte[] rfRead(long localAddress, long connectionId, int len) throws IOException {
return ((ConnectionBufferRFCOMM) getConnectionBuffer(localAddress, connectionId)).rfRead(len);
}
public void closeConnection(long localAddress, long connectionId) throws IOException {
Device localDevice = getDevice(localAddress);
if (localDevice == null) {
throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
}
localDevice.closeConnection(connectionId);
}
public int getSecurityOpt(long localAddress, long connectionId, int expected) throws IOException {
return ((ConnectionBuffer) getConnectionBuffer(localAddress, connectionId)).getSecurityOpt(expected);
}
public boolean encrypt(long localAddress, long connectionId, long remoteAddress, boolean on) throws IOException {
return ((ConnectionBuffer) getConnectionBuffer(localAddress, connectionId)).encrypt(remoteAddress, on);
}
public int l2RemoteDeviceReceiveMTU(long localAddress, long connectionId) throws IOException {
return ((ConnectionBufferL2CAP) getConnectionBuffer(localAddress, connectionId)).getRemoteReceiveMTU();
}
public boolean l2Ready(long localAddress, long connectionId) throws IOException {
return ((ConnectionBufferL2CAP) getConnectionBuffer(localAddress, connectionId)).ready();
}
public byte[] l2Receive(long localAddress, long connectionId, int len) throws IOException {
return ((ConnectionBufferL2CAP) getConnectionBuffer(localAddress, connectionId)).receive(len);
}
public void l2Send(long localAddress, long connectionId, byte[] data) throws IOException {
((ConnectionBufferL2CAP) getConnectionBuffer(localAddress, connectionId)).send(data);
}
}