/**
* 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;
import java.util.Random;
import java.util.Vector;
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.RemoteDevice;
import com.intel.bluetooth.emu.DeviceDescriptor;
/**
*
*/
class EmulatorDeviceInquiry implements DeviceInquiryRunnable {
private static final int DISCOVERY_DURATION_ALWAYS = 200;
private static final int DISCOVERY_DURATION_MINIMUM = 500;
private EmulatorLocalDevice localDevice;
private BluetoothStack bluetoothStack;
private DiscoveryListener discoveryListener;
private boolean deviceInquiryCanceled = false;
private Object canceledEvent = new Object();
private static Random rnd;
EmulatorDeviceInquiry(EmulatorLocalDevice localDevice, BluetoothStack bluetoothStack,
DiscoveryListener discoveryListener) {
this.localDevice = localDevice;
this.bluetoothStack = bluetoothStack;
this.discoveryListener = discoveryListener;
}
/*
* (non-Javadoc)
*
* @see com.intel.bluetooth.DeviceInquiryRunnable#runDeviceInquiry(com.intel.bluetooth.DeviceInquiryThread, int,
* javax.bluetooth.DiscoveryListener)
*/
public int runDeviceInquiry(DeviceInquiryThread startedNotify, int accessCode, DiscoveryListener listener)
throws BluetoothStateException {
try {
DeviceDescriptor[] devices = localDevice.getDeviceManagerService().getDiscoveredDevices(
localDevice.getAddress());
startedNotify.deviceInquiryStartedCallback();
long start = System.currentTimeMillis();
// Find first device
while (devices.length == 0) {
if (!randomWait(start, -1)) {
break;
}
devices = updateDiscoveredDevices(devices);
}
// Report devices and find a new one
int reportedIndex = 0;
while ((randomWait(start, reportedIndex)) || (reportedIndex < devices.length)) {
if (deviceInquiryCanceled) {
return DiscoveryListener.INQUIRY_TERMINATED;
}
if (reportedIndex < devices.length) {
DeviceDescriptor d = devices[reportedIndex];
// Device may be updated.
d = localDevice.getDeviceManagerService().getDeviceDescriptor(d.getAddress());
reportedIndex++;
RemoteDevice remoteDevice = RemoteDeviceHelper.createRemoteDevice(bluetoothStack, d.getAddress(), d
.getName(), false);
DeviceClass cod = new DeviceClass(d.getDeviceClass());
DebugLog.debug("deviceDiscovered address", remoteDevice.getBluetoothAddress());
DebugLog.debug("deviceDiscovered deviceClass", cod);
listener.deviceDiscovered(remoteDevice, cod);
}
devices = updateDiscoveredDevices(devices);
}
if (deviceInquiryCanceled) {
return DiscoveryListener.INQUIRY_TERMINATED;
}
return DiscoveryListener.INQUIRY_COMPLETED;
} finally {
bluetoothStack.cancelInquiry(discoveryListener);
}
}
private DeviceDescriptor[] updateDiscoveredDevices(DeviceDescriptor[] devices) {
DeviceDescriptor[] newDevices = localDevice.getDeviceManagerService().getDiscoveredDevices(
localDevice.getAddress());
Vector<DeviceDescriptor> discoveredDevice = new Vector<DeviceDescriptor>();
// Old device unchanged
for (int i = 0; i < devices.length; i++) {
discoveredDevice.addElement(devices[i]);
}
// Append new devices if any
newDevicesLoop: for (int i = 0; i < newDevices.length; i++) {
for (int k = 0; k < devices.length; k++) {
if (newDevices[i].getAddress() == devices[k].getAddress()) {
continue newDevicesLoop;
}
}
discoveredDevice.addElement(newDevices[i]);
}
return (DeviceDescriptor[]) discoveredDevice.toArray(new DeviceDescriptor[discoveredDevice.size()]);
}
private boolean randomWait(long start, int device) {
long duration = localDevice.getConfiguration().getDeviceInquiryDuration() * 1000;
if (duration <= 0) {
duration = DISCOVERY_DURATION_MINIMUM;
}
long now = System.currentTimeMillis();
if ((duration == 0) || (now > start + duration)) {
return false;
}
long timeout = duration / 7;
if (localDevice.getConfiguration().isDeviceInquiryRandomDelay()) {
if (rnd == null) {
rnd = new Random();
}
long timeleft = start + duration - now;
if (timeleft > 0) {
timeout = rnd.nextInt((int) timeleft);
}
}
if (device == 0) {
timeout += DISCOVERY_DURATION_ALWAYS;
}
// Limit wait till the end of the duration period
if (now + timeout > start + duration) {
timeout = start + duration - now;
}
if (timeout <= 0) {
return true;
}
synchronized (canceledEvent) {
try {
canceledEvent.wait(timeout);
} catch (InterruptedException e) {
deviceInquiryCanceled = true;
}
}
return true;
}
boolean cancelInquiry(DiscoveryListener listener) {
if (discoveryListener != listener) {
return false;
}
deviceInquiryCanceled = true;
synchronized (canceledEvent) {
canceledEvent.notifyAll();
}
return true;
}
/*
* (non-Javadoc)
*
* @see com.intel.bluetooth.DeviceInquiryRunnable#deviceDiscoveredCallback(javax.bluetooth.DiscoveryListener, long,
* int, java.lang.String, boolean)
*/
public void deviceDiscoveredCallback(DiscoveryListener listener, long deviceAddr, int deviceClass,
String deviceName, boolean paired) {
}
}